转载请标明出处:http://blog.csdn.net/android_ls/article/details/8586229
实践需求:通过GPS或者3G/2G网络(基站)定位,并将定位的结果(我当前的位置)标注在百度地图上。
当用户点击地图上代表“我的当前位置”的点时,显示当前我所在位置的详细信息。
一、通过GPS或者3G/2G网络(基站)定位。
基于百度地图定位SDK(版本v3.1)(一) .和百度地图定位SDK(版本v3.1)(二) .这两篇的积淀,导入百度提供的so和jar文件及在AndroidManifest.xml文件添加相应的配置等等就不罗嗦了,不了解的请查看前面的。
注意:由于要使用百度的提供的定位服务,所以在AndroidManifest.xml文件中一定要记得添加Service。(若没添加,运行不报错,也没有任何效果。)
设置定位参数,注册定位结果接收器。代码如下:
mLocationClient = new LocationClient(this.getApplicationContext());
mLocationListener = new MyLocationListener();
mLocationClient.registerLocationListener(mLocationListener);
LocationClientOption locationOption = new LocationClientOption();
locationOption.setOpenGps(true);
locationOption.setCoorType("bd09ll");
locationOption.setPriority(LocationClientOption.GpsFirst);
locationOption.setAddrType("all");
locationOption.setProdName("通过GPS定位");
mLocationClient.setLocOption(locationOption);
Log.i(TAG, "BaiduMapMyLocationActivity 开启定位");
mLocationClient.start();
二、将定位的结果(我当前的位置)标注在百度地图上。
1、在前面为 mLocationClient对象注册了BDLocationListener,自定义类实现BDLocationListener接口,处理定位得到的结果,具体代码如下:
class MyLocationListener implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
if (location == null) {
return;
}
Log.i(TAG, "BaiduMapMyLocationActivity onReceiveLocation()");
// TODO 为方便测试查看
testLog(location);
// 在地图上标注定位得到我当前的位置
markLocation(location);
mBDLocation = location;
}
@Override
public void onReceivePoi(BDLocation arg0) {
}
}
2、构建一个负责在地图上显示用户当前位置的Overlay对象及为该Overlay对象设置数据。
mLocationOverlay = new LocationOverlay(mMapView);
// 百度官方API文档解释:打开指南针,但是我试验觉得默认指南针就是打开的
// mLocationOverlay.enableCompass();
locData = new LocationData();
mLocationOverlay.setData(locData);
3、将负责在地图上显示用户当前位置的Overlay对象添加到覆盖物列表中,并刷新地图视图view。
mMapView.getOverlays().add(mLocationOverlay);
mMapView.refresh();
4、将我的当前位置移动到地图的中心点
mMapController.animateTo(new GeoPoint(
(int) (locData.latitude * 1e6),
(int) (locData.longitude * 1e6)));
三、当用户点击地图上代表“我的当前位置”的点时,显示当前我所在位置的详细信息。自定义类继承MyLocationOverlay,重写 protected boolean dispatchTap() {}方法,在方法体中添加相应的处理即可。
class LocationOverlay extends MyLocationOverlay {
public LocationOverlay(MapView mapView) {
super(mapView);
}
// 处理在“我的位置”坐标上的点击事件。
@Override
protected boolean dispatchTap() {
Log.i(TAG, "BaiduMapMyLocationActivity 处理在“我的位置”坐标上的点击事件 dispatchTap()");
if (mBDLocation != null) {
showLocation(mBDLocation);
}
return super.dispatchTap();
}
}
四、运行效果图
点击地图上的蓝色指南针图标,效果图如下:
点击上图黑色区域,该区域消失;点击“重新定位”按钮,重新获取我当前的位置。
注:我在房子采用的是Wifi网络定位,所以地址信息不为null。
五、我发现存在的问题:
1、百度最新API与API文档中描述个别不符
a. 这行mLocationOverlay.enableCompass();代码,百度官方API文档解释:打开指南针,但是我经过测试,觉得默认指南针就是打开的。
b. 地图引擎管理类BMapManager,API文档中描述:boolean start() // 开启百度地图API;boolean stop() // 终止百度地图API,调用此函数后,不会再发生回调。实际上使用最新的SDK中的BMapManager类创建的对象已经没有什么start、stop方法。
2、当调用 mLocationClient.start(); (LocationClient类实例化后,调用它的start方法。)后,会重新执行一次BaiduMapApplication(# class BaiduMapApplication extends Application{})的onCreate()回调方法。目前道没发现影响使用,但是我个人觉得:若之前已执行过,也就是说初始化过地图引擎类,就不应该再次初始化。不知道这个算是个问题不?官方给的demo里也存在这个问题,怎么解决?(资源浪费使用)
六、完整代码:
AndroidManifest.xml文件配置:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.easi.baidu.map"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:name=".BaiduMapApplication" >
<activity
android:configChanges="keyboardHidden|orientation"
android:label="@string/app_name"
android:name=".BaiduMapMyLocationActivity"
android:screenOrientation="sensor" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:enabled="true"
android:name="com.baidu.location.f"
android:process=":remote" />
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" >
</uses-permission>
<uses-permission android:name="android.permission.INTERNET" >
</uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" >
</uses-permission>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" >
</uses-permission>
<uses-permission android:name="android.permission.READ_PHONE_STATE" >
</uses-permission>
<uses-permission android:name="android.permission.CALL_PHONE" >
</uses-permission>
<permission android:name="android.permission.BAIDU_LOCATION_SERVICE" >
</permission>
<uses-permission android:name="android.permission.BAIDU_LOCATION_SERVICE" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" >
</uses-permission>
<uses-permission android:name="android.permission.ACCES_MOCK_LOCATION" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_GPS" />
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="false"
android:resizeable="true"
android:smallScreens="true" />
</manifest>
初始化地图引擎对象,存放共享资源,继承自Application。
package com.easi.baidu.map;
import android.app.Application;
import android.content.Context;
import android.util.Log;
import android.widget.Toast;
import com.baidu.mapapi.BMapManager;
import com.baidu.mapapi.MKGeneralListener;
import com.baidu.mapapi.map.MKEvent;
/**
* 初始化地图引擎对象,存放共享资源。
* 需要在AndroidMinifest.xml文件中的application标签添加name属性。
* {@link #<application android:name=".BaiduMapApplication" >}
* @author android_ls
*/
public class BaiduMapApplication extends Application {
/**
* 申请的百度地图API Key密钥
*/
private static final String BAIDU_MAP_KEY = "8BB7F0E5C9C77BD6B9B655DB928B74B6E2D838FD";
/**
* Log打印标签
*/
private static final String TAG = "BaiduMapApplication";
/* package */BMapManager mMapManager;
/* package */Context mContext;
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "BaiduMapApplication onCreate()");
mContext = getApplicationContext();
mMapManager = new BMapManager(getApplicationContext());
initMapManager();
}
/**
* 初始化BMapManager对象
*
* @return boolean
*/
public void initMapManager() {
boolean result = mMapManager.init(BAIDU_MAP_KEY, new MKGeneralListener() {
@Override
public void onGetNetworkState(int error) {
if (error == MKEvent.ERROR_NETWORK_CONNECT) {
Toast.makeText(mContext, "您的网络出错啦!", Toast.LENGTH_LONG).show();
} else if (error == MKEvent.ERROR_NETWORK_DATA) {
Toast.makeText(mContext, "输入正确的检索条件!", Toast.LENGTH_LONG).show();
}
}
@Override
public void onGetPermissionState(int error) {
if (error == MKEvent.ERROR_PERMISSION_DENIED) {
// 授权Key错误:
Toast.makeText(mContext, "您的授权Key出错!", Toast.LENGTH_LONG).show();
}
}
});
if (!result) {
Toast.makeText(mContext, "初始化地图引擎失败!", Toast.LENGTH_LONG).show();
} else {
Log.i(TAG, "地图引擎初始化成功!");
}
}
@Override
public void onTerminate() {
Log.i(TAG, "BaiduMapApplication onTerminate()");
if (mMapManager != null) {
mMapManager.destroy();
mMapManager = null;
}
super.onTerminate();
}
}
需要用到百度地图的Activity基类,继承自Activity
package com.easi.baidu.map;
import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.Log;
import com.baidu.mapapi.BMapManager;
import com.baidu.mapapi.map.MapController;
import com.baidu.mapapi.map.MapView;
/**
* 需要用到百度地图的Activity基类
* #public class BaiduMapMyLocationActivity extends BaiduMapBaseActivity{}
* @author android_ls
*/
public abstract class BaiduMapBaseActivity extends Activity {
/**
* Application对象的引用
*/
protected BaiduMapApplication mApplication;
/**
* 显示地图的View组件
*/
protected MapView mMapView;
/**
* MapView控制器对象的引用
*/
protected MapController mMapController;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mApplication = (BaiduMapApplication) this.getApplication();
if (mApplication.mMapManager == null) {
Log.e("BaiduMapApplication", "BaiduMapBaseActivity mApplication.mMapManager is NULL!");
mApplication.mMapManager = new BMapManager(mApplication.mContext);
mApplication.initMapManager();
}
setContentView(getLayoutId());
mMapView = (MapView) this.findViewById(getMapViewId());
mMapController = mMapView.getController();
}
/**
* 获取代表布局文件的ID
* #setContentView(getLayoutId());
* @return int
*/
public abstract int getLayoutId();
/**
* 获取代表MapView对象的组件ID
* #(MapView) this.findViewById(getMapViewId());
* @return int
*/
public abstract int getMapViewId();
@Override
protected void onPause() {
mMapView.onPause();
super.onPause();
}
@Override
protected void onResume() {
mMapView.onResume();
super.onResume();
}
@Override
protected void onDestroy() {
mMapView.destroy();
super.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mMapView.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mMapView.onRestoreInstanceState(savedInstanceState);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
}
定位功能具体实现类,继承自BaiduMapBaseActivity
package com.easi.baidu.map;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.map.LocationData;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.MyLocationOverlay;
import com.baidu.platform.comapi.basestruct.GeoPoint;
/**
* 提供通过GPS或者3G/2G网络(基站)定位,并将定位的结果(我当前的位置)标注在百度地图上。
* 当用户点击地图上代表“我的当前位置”的点时,显示当前我所在位置的详细信息。
*
* 注:当gps可用,而且获取了定位结果时,不再发起网络请求,直接返回给用户坐标。
* 如果gps不可用,再发起网络请求,进行定位。
* @author android_ls
*
*/
public class BaiduMapMyLocationActivity extends BaiduMapBaseActivity {
/**
* Log打印标签
*/
private static final String TAG = "BaiduMapMyLocationActivity";
/**
* 定位SDK的核心类
*/
private LocationClient mLocationClient;
/**
* 显示定位结果详细信息的View
*/
private TextView tvLocationResult;
/**
* 标注我的位置的覆盖物
* # class LocationOverlay extends MyLocationOverlay{}
*/
private MyLocationOverlay mLocationOverlay;
/**
* 我的位置信息数据
*/
private LocationData locData;
/**
* 定位结果处理器
* # class MyLocationListener implements BDLocationListener{}
*/
private MyLocationListener mLocationListener;
/**
* 暂时缓存我的当前位置数据
*/
private BDLocation mBDLocation;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "BaiduMapMyLocationActivity onCreate()");
mMapController.setZoom(15);
mMapController.enableClick(true);
tvLocationResult = (TextView) this.findViewById(R.id.tv_location_result);
mLocationClient = new LocationClient(this.getApplicationContext());
mLocationListener = new MyLocationListener();
mLocationClient.registerLocationListener(mLocationListener);
LocationClientOption locationOption = new LocationClientOption();
locationOption.setOpenGps(true);
locationOption.setCoorType("bd09ll");
locationOption.setPriority(LocationClientOption.GpsFirst);
locationOption.setAddrType("all");
locationOption.setProdName("通过GPS定位");
mLocationClient.setLocOption(locationOption);
Log.i(TAG, "BaiduMapMyLocationActivity 开启定位");
mLocationClient.start();
// 重新定位
findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mLocationClient != null && mLocationClient.isStarted())
mLocationClient.requestLocation();
}
});
mLocationOverlay = new LocationOverlay(mMapView);
// 百度官方API文档解释:打开指南针,但是我试验觉得默认指南针就是打开的
// mLocationOverlay.enableCompass();
locData = new LocationData();
tvLocationResult.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tvLocationResult.setVisibility(View.GONE);
}
});
}
class LocationOverlay extends MyLocationOverlay {
public LocationOverlay(MapView mapView) {
super(mapView);
}
// 处理在“我的位置”坐标上的点击事件。
@Override
protected boolean dispatchTap() {
Log.i(TAG, "BaiduMapMyLocationActivity 处理在“我的位置”坐标上的点击事件 dispatchTap()");
if (mBDLocation != null) {
showLocation(mBDLocation);
}
return super.dispatchTap();
}
}
/**
* 显示我当前位置的详细信息
* @param location
*/
private void showLocation(BDLocation location) {
StringBuffer sb = new StringBuffer(256);
sb.append(" time : ");
sb.append(location.getTime());
sb.append("\n error code : ");
sb.append(location.getLocType());
sb.append("\n latitude : ");
sb.append(location.getLatitude());
sb.append("\n lontitude : ");
sb.append(location.getLongitude());
// 判断是否有定位精度半径
if (location.hasRadius()) {
// 获取定位精度半径,单位是米
float accuracy = location.getRadius();
Log.i(TAG, "accuracy = " + accuracy);
sb.append("\n radius : ");
sb.append(location.getRadius());
}
if (location.getLocType() == BDLocation.TypeGpsLocation) {
if (location.hasSpeed()) {
sb.append("\n speed : ");
sb.append(location.getSpeed());
}
if (location.hasSateNumber()) {
sb.append("\n satellite : ");
sb.append(location.getSatelliteNumber());
}
} else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {
// 获取反地理编码。 只有使用网络定位的情况下,才能获取当前位置的反地理编码描述。
if (location.hasAddr()) {
String address = location.getAddrStr();
Log.i(TAG, "address = " + address);
sb.append("\n addr : ");
sb.append(address);
}
}
tvLocationResult.setVisibility(View.VISIBLE);
tvLocationResult.setText(sb);
}
/**
* 在地图上标注定位得到我当前的位置
* @param location
*/
private void markLocation(BDLocation location) {
locData.latitude = location.getLatitude();
locData.longitude = location.getLongitude();
locData.direction = location.getDerect();
// 判断是否有定位精度半径
if (location.hasRadius()) {
// 获取定位精度半径,单位是米
locData.accuracy = location.getRadius();
}
mLocationOverlay.setData(locData);
mMapView.getOverlays().add(mLocationOverlay);
mMapView.refresh();
// 将我的当前位置移动到地图的中心点
mMapController.animateTo(new GeoPoint(
(int) (locData.latitude * 1e6),
(int) (locData.longitude * 1e6)));
}
class MyLocationListener implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
if (location == null) {
return;
}
Log.i(TAG, "BaiduMapMyLocationActivity onReceiveLocation()");
// TODO 为方便测试查看
testLog(location);
// 在地图上标注定位得到我当前的位置
markLocation(location);
mBDLocation = location;
}
@Override
public void onReceivePoi(BDLocation arg0) {
}
}
/**
* 打印测试LOG信息
* @param location
*/
private void testLog(BDLocation location) {
String province = location.getProvince(); // 获取省份信息
String city = location.getCity(); // 获取城市信息
String district = location.getDistrict(); // 获取区县信息
Log.i(TAG, "province = " + province);
Log.i(TAG, "city = " + city);
Log.i(TAG, "district = " + district);
int type = location.getLocType();
Log.i(TAG, "当前定位采用的类型是:type = " + type);
String coorType = location.getCoorType();
Log.i(TAG, "坐标系类型:coorType = " + coorType);
float derect = location.getDerect();
Log.i(TAG, "derect = " + derect);
}
@Override
public int getLayoutId() {
return R.layout.main;
}
@Override
public int getMapViewId() {
return R.id.bmapView;
}
@Override
protected void onDestroy() {
Log.i(TAG, "BaiduMapMyLocationActivity onDestroy() start");
mLocationClient.stop();
mLocationClient.unRegisterLocationListener(mLocationListener);
this.mApplication.onTerminate();
super.onDestroy();
Log.i(TAG, "BaiduMapMyLocationActivity onDestroy() end");
}
}