[Android]百度地圖POI檢索

寫在前面
本來想使用百度定位的SDK把定位功能實現了,可無奈遇上個坑到寫這篇blog為止都還沒有解決。故所以把使用百度地圖SDK實現簡單的POI檢索功能和遇到的坑先做一個總結。

下載.os和jar包

  1. 如果需要使用自定義的功能,最好不要分別下載。
    例如之前我只是想先簡單的實現POI檢索功能,所以只下載了跟百度地圖相關的SDK,實現了之后覺得單調,決定加入定位功能的時候再單獨去下載了定位相關的SDK,坑就出現了,引入.os和jar之后,
    出現 java.lang.NoSuchMethodError: No direct method <init> 這樣的錯誤。只要我們下載的時候勾選要下載的SDK統一下載,就不會出現這樣的bug了。
    這里寫圖片描述

    2.jar和.os引入之后,仍然無法使用(初始化SDK)。
    解決方案是在app的build.gradle加入
android{
    ...
    sourceSets {
           main() {
           jniLibs.srcDirs = ['libs']
           }
    }
}

這在地圖的文檔沒有說到,但在定位的文檔才可以找到。小小的吐槽一下百度文檔...

地圖初始化

  • 添加密匙 (申請百度賬號,密匙在這里就不寫了。很簡單)
<application>  
    <meta-data  
        android:name="com.baidu.lbsapi.API_KEY"  
        android:value="開發者 key" />  
</application>
  • 添加所需權限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
  • 在布局xml文件中添加地圖控件
<com.baidu.mapapi.map.MapView  
    android:id="@+id/bmapView"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent"  
    android:clickable="true" />
  • 在應用程序創建時初始化 SDK
public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        /***
         * 初始化定位sdk,建議在Application中創建
         */
        SDKInitializer.initialize(getApplicationContext());
    }
}
  • 管理地圖生命周期
 @Override  
    protected void onDestroy() {  
        super.onDestroy();  
        //在activity執行onDestroy時執行mMapView.onDestroy(),實現地圖生命周期管理  
        mMapView.onDestroy();  
    }  
    @Override  
    protected void onResume() {  
        super.onResume();  
        //在activity執行onResume時執行mMapView. onResume (),實現地圖生命周期管理  
        mMapView.onResume();  
        }  
    @Override  
    protected void onPause() {  
        super.onPause();  
        //在activity執行onPause時執行mMapView. onPause (),實現地圖生命周期管理  
        mMapView.onPause();  
        }  
    }

當然,還要在你的AndroidManifest中把你的Application設置成我們自定義的MyApplication

完成以上步驟運行,就能把地圖顯示出來,在沒實現定位功能之前,初始化位置是在北京。

POI檢索

  • 初始化POI檢索對象
/**
 *實例化
 */
PoiSearch mPoiSearch = PoiSearch.newInstance();
/**
 *回調
 */
OnGetPoiSearchResultListener poiListener = new OnGetPoiSearchResultListener(){  
@Override
    public void onGetPoiResult(PoiResult result){  
    //獲取POI檢索結果  
    }  
    @Override
    public void onGetPoiDetailResult(PoiDetailResult result){  
    //獲取Place詳情頁檢索結果  
    }  
    @Override
    public void onGetPoiIndoorResult(PoiIndoorResult poiIndoorResult) {
    //獲取門址類列表
    }
};
/**
 *設置監聽
 */
mPoiSearch.setOnGetPoiSearchResultListener(poiListener);
  • 檢索
    城市檢索
 mPoiSearch.searchInCity((new PoiCitySearchOption())
                .city("深圳")//城市
                .keyword("美食")//檢索關鍵字
                .pageNum(0)//分頁編碼
                .pageCapacity(5));//每頁容量,默認10條

周邊檢索

mPoiSearch.searchNearby(new PoiNearbySearchOption()
        //搜索結果排序規則,PoiSortType.comprehensive->距離排序
        .sortType(PoiSortType.comprehensive) ->綜合排序;
        .radius(1000)//檢索半徑范圍,單位:米
        .location(LatLng location)) //檢索位置

區域檢索

 mPoiSearch.searchInBound(new PoiBoundSearchOption()
        .bound(LatLngBounds bound)//檢索范圍
 );

構建LatLngBounds對象

        LatLng southwest = new LatLng(latitude - 0.01, longitude - 0.012);// 西南  
        LatLng northeast = new LatLng(latitude + 0.01, longitude + 0.012);// 東北  
        LatLngBounds bounds = new LatLngBounds.Builder().include(southwest)  
                .include(northeast).build();// 得到一個地理范圍對象   

所有檢索的結果都在poiListener中回調
在每一個POI中都包含一個"Uid"的字段,如果我們需要知道某個POI的詳情,我們可以

mPoiSearch.searchPoiDetail((new PoiDetailSearchOption()).poiUid(uid));

檢索的結果同樣是在poiListener中回調
詳細的文檔內容在這里

在回調中得到的是一條條的信息,純文本看著多沒意思,展示的地圖還沒用上。那我們就可以給每個檢索出來的POI在地圖上標注起來,瞬間好玩多了!

  • 覆蓋物
    自定義 PoiOverlay 類
private class MyPoiOverlay extends PoiOverlay {  
    public MyPoiOverlay(BaiduMap baiduMap) {  
        super(baiduMap);  
    }  
    @Override  
    public boolean onPoiClick(int index) {  
        super.onPoiClick(index);  
        return true;  
    }  
}

在POI檢索回調接口中添加自定義的PoiOverlay

public void onGetPoiResult(PoiResult result) {  
    if (result == null || result.error == SearchResult.ERRORNO.RESULT_NOT_FOUND) {  
        return;  
    }  
    if (result.error == SearchResult.ERRORNO.NO_ERROR) {  
        mBaiduMap.clear();  
        //創建PoiOverlay  
        PoiOverlay overlay = new MyPoiOverlay(mBaiduMap);  
        //設置overlay可以處理標注點擊事件  
        mBaiduMap.setOnMarkerClickListener(overlay);  
        //設置PoiOverlay數據  
        overlay.setData(result);  
        //添加PoiOverlay到地圖中  
        overlay.addToMap();  
        overlay.zoomToSpan();  
        return;  
    }  
}

這樣,檢索出來的POI在地圖上就完成標注了


這里寫圖片描述

寫到這里,簡單的地圖的POI功能就完成了。

寫在最后
簡簡單單的POI檢索當然不能滿足我們日益膨脹的心呀!所以現在努力實現定位的功能,到時候再更新blog,分享給那些還沒了解定位但即將使用的筒靴一個開篇指引和遇到的坑。加油!
note:
在覆蓋物中設計到兩個類:PoiOverlay 和OverlayManager在SDK中是沒有的,但在官方的Demo中給出。這里是給沒有下載Demo的筒靴的一個幫助,希望可以共同進步!

12月6號更新:
今天什么也沒改跑了一遍Demo,原先實現的定位功能突然就好了... 船到橋頭自然直呀
貼一下定位的代碼,基本照搬官方文檔上的代碼,就不作過多的解釋了

    /**
     * 封裝定位結果和時間的實體類
     *
     * @author baidu
     */
    class LocationEntity {
        BDLocation location;
        long time;
    }

    private void initlocalMap() {
        mBaiduMap = mMapView.getMap();
        mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
        mBaiduMap.setMapStatus(MapStatusUpdateFactory.zoomTo(15));
        mBaiduMap.setMyLocationEnabled(true);
        locService = ((MyApplication) getApplication()).locationService;
        LocationClientOption mOption = locService.getDefaultLocationClientOption();
        mOption.setOpenGps(true);
        mOption.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        mOption.setCoorType("bd09ll");

//        locService.setLocationOption(mOption);
//        locService.registerListener(listener);
//        locService.start();

        mClient = new LocationClient(this);
        mClient.setLocOption(mOption);
        mClient.registerLocationListener(listener);
        mClient.start();
    }

    /***
     * 定位結果回調,在此方法中處理定位結果
     */
    BDLocationListener listener = new BDLocationListener() {
        @Override
        public void onReceiveLocation(BDLocation location) {
            if (location != null && (location.getLocType() == 161 || location.getLocType() == 66)) {
                Message locMsg = locHander.obtainMessage();
                Bundle locData;
                locData = Algorithm(location);
                if (locData != null) {
                    locData.putParcelable("loc", location);
                    locMsg.setData(locData);
                    locHander.sendMessage(locMsg);
                }
            }
        }
    };

    /***
     * 平滑策略代碼實現方法,主要通過對新定位和歷史定位結果進行速度評分,
     * 來判斷新定位結果的抖動幅度,如果超過經驗值,則判定為過大抖動,進行平滑處理,若速度過快,
     * 則推測有可能是由于運動速度本身造成的,則不進行低速平滑處理 ╭(●`?′●)╯
     *
     * @param location
     * @return Bundle
     */
    private Bundle Algorithm(BDLocation location) {
        Bundle locData = new Bundle();
        double curSpeed = 0;
        if (locationList.isEmpty() || locationList.size() < 2) {
            LocationEntity temp = new LocationEntity();
            temp.location = location;
            temp.time = System.currentTimeMillis();
            locData.putInt("iscalculate", 0);
            locationList.add(temp);
        } else {
            if (locationList.size() > 5)
                locationList.removeFirst();
            double score = 0;
            for (int i = 0; i < locationList.size(); ++i) {
                LatLng lastPoint = new LatLng(locationList.get(i).location.getLatitude(),
                        locationList.get(i).location.getLongitude());
                LatLng curPoint = new LatLng(location.getLatitude(), location.getLongitude());
                double distance = DistanceUtil.getDistance(lastPoint, curPoint);
                curSpeed = distance / (System.currentTimeMillis() - locationList.get(i).time) / 1000;
                score += curSpeed * EARTH_WEIGHT[i];
            }
            if (score > 0.00000999 && score < 0.00005) { // 經驗值,開發者可根據業務自行調整,也可以不使用這種算法
                location.setLongitude(
                        (locationList.get(locationList.size() - 1).location.getLongitude() + location.getLongitude())
                                / 2);
                location.setLatitude(
                        (locationList.get(locationList.size() - 1).location.getLatitude() + location.getLatitude())
                                / 2);
                locData.putInt("iscalculate", 1);
            } else {
                locData.putInt("iscalculate", 0);
            }
            LocationEntity newLocation = new LocationEntity();
            newLocation.location = location;
            newLocation.time = System.currentTimeMillis();
            locationList.add(newLocation);

        }
        return locData;
    }

    LatLng point;

    /***
     * 接收定位結果消息,并顯示在地圖上
     */
    private Handler locHander = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            super.handleMessage(msg);
            try {
                BDLocation location = msg.getData().getParcelable("loc");
                int iscal = msg.getData().getInt("iscalculate");
                if (location != null) {
                    point = new LatLng(location.getLatitude(), location.getLongitude());
                    // 構建Marker圖標
                    BitmapDescriptor bitmap = null;
                    if (iscal == 0) {
                        bitmap = BitmapDescriptorFactory.fromResource(R.drawable.huaji); // 非推算結果
                    } else {
                        bitmap = BitmapDescriptorFactory.fromResource(R.drawable.icon_openmap_focuse_mark); // 推算結果
                    }

                    // 構建MarkerOption,用于在地圖上添加Marker
                    OverlayOptions option = new MarkerOptions().position(point).icon(bitmap);
                    // 在地圖上添加Marker,并顯示
                    mBaiduMap.addOverlay(option);
                    mBaiduMap.setMapStatus(MapStatusUpdateFactory.newLatLng(point));
                }
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
    };

這里我們拿到定位返回的LatLng,然后我們檢索定位周邊的POI
修改原先的search方法

private void search(String searchPoi) {
        mPoiSearch = PoiSearch.newInstance();
        /*mPoiSearch.searchInCity((new PoiCitySearchOption())
                .city("深圳")
                .keyword(searchPoi)
                .pageNum(1)
                .pageCapacity(5));*/
        mPoiSearch.searchNearby(new PoiNearbySearchOption()
                .keyword(searchPoi)
                .location(point)
                .radius(2000)
                .pageNum(0)
                .pageCapacity(5)
                .sortType(PoiSortType.distance_from_near_to_far));
        mPoiSearch.setOnGetPoiSearchResultListener(poiListener);
    }

這樣,就只能直接檢索你所在位置的POI了

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容