寫(xiě)在前面
本來(lái)想使用百度定位的SDK把定位功能實(shí)現(xiàn)了斩萌,可無(wú)奈遇上個(gè)坑到寫(xiě)這篇blog為止都還沒(méi)有解決畅形。故所以把使用百度地圖SDK實(shí)現(xiàn)簡(jiǎn)單的POI檢索功能和遇到的坑先做一個(gè)總結(jié)置吓。
下載.os和jar包
坑
- 如果需要使用自定義的功能沦补,最好不要分別下載踢俄。
例如之前我只是想先簡(jiǎn)單的實(shí)現(xiàn)POI檢索功能蚊逢,所以只下載了跟百度地圖相關(guān)的SDK,實(shí)現(xiàn)了之后覺(jué)得單調(diào)箫章,決定加入定位功能的時(shí)候再單獨(dú)去下載了定位相關(guān)的SDK烙荷,坑就出現(xiàn)了,引入.os和jar之后檬寂,
出現(xiàn)java.lang.NoSuchMethodError: No direct method <init>
這樣的錯(cuò)誤终抽。只要我們下載的時(shí)候勾選要下載的SDK統(tǒng)一下載,就不會(huì)出現(xiàn)這樣的bug了桶至。
2.jar和.os引入之后昼伴,仍然無(wú)法使用(初始化SDK)。
解決方案是在app的build.gradle加入
android{
...
sourceSets {
main() {
jniLibs.srcDirs = ['libs']
}
}
}
這在地圖的文檔沒(méi)有說(shuō)到镣屹,但在定位的文檔才可以找到圃郊。小小的吐槽一下百度文檔...
地圖初始化
- 添加密匙 (申請(qǐng)百度賬號(hào),密匙在這里就不寫(xiě)了女蜈。很簡(jiǎn)單)
<application>
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="開(kāi)發(fā)者 key" />
</application>
- 添加所需權(quán)限
<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" />
- 在應(yīng)用程序創(chuàng)建時(shí)初始化 SDK
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
/***
* 初始化定位sdk持舆,建議在Application中創(chuàng)建
*/
SDKInitializer.initialize(getApplicationContext());
}
}
- 管理地圖生命周期
@Override
protected void onDestroy() {
super.onDestroy();
//在activity執(zhí)行onDestroy時(shí)執(zhí)行mMapView.onDestroy(),實(shí)現(xiàn)地圖生命周期管理
mMapView.onDestroy();
}
@Override
protected void onResume() {
super.onResume();
//在activity執(zhí)行onResume時(shí)執(zhí)行mMapView. onResume ()伪窖,實(shí)現(xiàn)地圖生命周期管理
mMapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
//在activity執(zhí)行onPause時(shí)執(zhí)行mMapView. onPause ()逸寓,實(shí)現(xiàn)地圖生命周期管理
mMapView.onPause();
}
}
當(dāng)然,還要在你的AndroidManifest中把你的Application設(shè)置成我們自定義的MyApplication
完成以上步驟運(yùn)行,就能把地圖顯示出來(lái)覆山,在沒(méi)實(shí)現(xiàn)定位功能之前竹伸,初始化位置是在北京。
POI檢索
- 初始化POI檢索對(duì)象
/**
*實(shí)例化
*/
PoiSearch mPoiSearch = PoiSearch.newInstance();
/**
*回調(diào)
*/
OnGetPoiSearchResultListener poiListener = new OnGetPoiSearchResultListener(){
@Override
public void onGetPoiResult(PoiResult result){
//獲取POI檢索結(jié)果
}
@Override
public void onGetPoiDetailResult(PoiDetailResult result){
//獲取Place詳情頁(yè)檢索結(jié)果
}
@Override
public void onGetPoiIndoorResult(PoiIndoorResult poiIndoorResult) {
//獲取門(mén)址類列表
}
};
/**
*設(shè)置監(jiān)聽(tīng)
*/
mPoiSearch.setOnGetPoiSearchResultListener(poiListener);
-
檢索
城市檢索
mPoiSearch.searchInCity((new PoiCitySearchOption())
.city("深圳")//城市
.keyword("美食")//檢索關(guān)鍵字
.pageNum(0)//分頁(yè)編碼
.pageCapacity(5));//每頁(yè)容量簇宽,默認(rèn)10條
周邊檢索
mPoiSearch.searchNearby(new PoiNearbySearchOption()
//搜索結(jié)果排序規(guī)則勋篓,PoiSortType.comprehensive->距離排序
.sortType(PoiSortType.comprehensive) ->綜合排序;
.radius(1000)//檢索半徑范圍晦毙,單位:米
.location(LatLng location)) //檢索位置
區(qū)域檢索
mPoiSearch.searchInBound(new PoiBoundSearchOption()
.bound(LatLngBounds bound)//檢索范圍
);
構(gòu)建LatLngBounds對(duì)象
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();// 得到一個(gè)地理范圍對(duì)象
所有檢索的結(jié)果都在poiListener中回調(diào)
在每一個(gè)POI中都包含一個(gè)"Uid"的字段生巡,如果我們需要知道某個(gè)POI的詳情,我們可以
mPoiSearch.searchPoiDetail((new PoiDetailSearchOption()).poiUid(uid));
檢索的結(jié)果同樣是在poiListener中回調(diào)
詳細(xì)的文檔內(nèi)容在這里
在回調(diào)中得到的是一條條的信息见妒,純文本看著多沒(méi)意思孤荣,展示的地圖還沒(méi)用上。那我們就可以給每個(gè)檢索出來(lái)的POI在地圖上標(biāo)注起來(lái)须揣,瞬間好玩多了盐股!
- 覆蓋物
自定義 PoiOverlay 類
private class MyPoiOverlay extends PoiOverlay {
public MyPoiOverlay(BaiduMap baiduMap) {
super(baiduMap);
}
@Override
public boolean onPoiClick(int index) {
super.onPoiClick(index);
return true;
}
}
在POI檢索回調(diào)接口中添加自定義的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();
//創(chuàng)建PoiOverlay
PoiOverlay overlay = new MyPoiOverlay(mBaiduMap);
//設(shè)置overlay可以處理標(biāo)注點(diǎn)擊事件
mBaiduMap.setOnMarkerClickListener(overlay);
//設(shè)置PoiOverlay數(shù)據(jù)
overlay.setData(result);
//添加PoiOverlay到地圖中
overlay.addToMap();
overlay.zoomToSpan();
return;
}
}
這樣,檢索出來(lái)的POI在地圖上就完成標(biāo)注了
寫(xiě)到這里耻卡,簡(jiǎn)單的地圖的POI功能就完成了疯汁。
寫(xiě)在最后
簡(jiǎn)簡(jiǎn)單單的POI檢索當(dāng)然不能滿足我們?nèi)找媾蛎浀男难剑∷袁F(xiàn)在努力實(shí)現(xiàn)定位的功能卵酪,到時(shí)候再更新blog幌蚊,分享給那些還沒(méi)了解定位但即將使用的筒靴一個(gè)開(kāi)篇指引和遇到的坑谤碳。加油!
note:
在覆蓋物中設(shè)計(jì)到兩個(gè)類:PoiOverlay 和OverlayManager在SDK中是沒(méi)有的溢豆,但在官方的Demo中給出蜒简。這里是給沒(méi)有下載Demo的筒靴的一個(gè)幫助,希望可以共同進(jìn)步!
12月6號(hào)更新:
今天什么也沒(méi)改跑了一遍Demo漩仙,原先實(shí)現(xiàn)的定位功能突然就好了... 船到橋頭自然直呀
貼一下定位的代碼搓茬,基本照搬官方文檔上的代碼,就不作過(guò)多的解釋了
/**
* 封裝定位結(jié)果和時(shí)間的實(shí)體類
*
* @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();
}
/***
* 定位結(jié)果回調(diào)队他,在此方法中處理定位結(jié)果
*/
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);
}
}
}
};
/***
* 平滑策略代碼實(shí)現(xiàn)方法卷仑,主要通過(guò)對(duì)新定位和歷史定位結(jié)果進(jìn)行速度評(píng)分,
* 來(lái)判斷新定位結(jié)果的抖動(dòng)幅度麸折,如果超過(guò)經(jīng)驗(yàn)值锡凝,則判定為過(guò)大抖動(dòng),進(jìn)行平滑處理,若速度過(guò)快磕谅,
* 則推測(cè)有可能是由于運(yùn)動(dòng)速度本身造成的私爷,則不進(jìn)行低速平滑處理 ╭(●`?′●)╯
*
* @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) { // 經(jīng)驗(yàn)值,開(kāi)發(fā)者可根據(jù)業(yè)務(wù)自行調(diào)整,也可以不使用這種算法
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;
/***
* 接收定位結(jié)果消息膊夹,并顯示在地圖上
*/
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());
// 構(gòu)建Marker圖標(biāo)
BitmapDescriptor bitmap = null;
if (iscal == 0) {
bitmap = BitmapDescriptorFactory.fromResource(R.drawable.huaji); // 非推算結(jié)果
} else {
bitmap = BitmapDescriptorFactory.fromResource(R.drawable.icon_openmap_focuse_mark); // 推算結(jié)果
}
// 構(gòu)建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了