调用百度地图SDK来进行定位,
参考了百度地图的官方Demo
注意点:
1. 首先要获取开发密钥,在application中添加:
<application>
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="开发者 key" />
</application>
2. 需要定义Application
LocationApplication.java
/**
* 主Application
* 直接拷贝com.baidu.location.service包到自己的工程下,简单配置即可获取定位结果,也可以根据demo内容自行封装
*/
public class LocationApplication extends Application {
public LocationService locationService;
public Vibrator mVibrator;
@Override
public void onCreate() {
super.onCreate();
/***
* 初始化定位sdk,建议在Application中创建
*/
locationService = new LocationService(getApplicationContext());
mVibrator = (Vibrator) getApplicationContext().getSystemService(Service.VIBRATOR_SERVICE);
// WriteLog.getInstance().init(); // 初始化日志
SDKInitializer.initialize(getApplicationContext());
}
}
在application中添加:
<application
android:name="com.dingding.mylocation.LocationApplication"
3. 定义Service
LocationService.java
public class LocationService {
private LocationClient client = null;
private LocationClientOption mOption,DIYoption;
private Object objLock = new Object();
/***
*
* @param locationContext
*/
public LocationService(Context locationContext){
synchronized (objLock) {
if(client == null){
client = new LocationClient(locationContext);
client.setLocOption(getDefaultLocationClientOption());
}
}
}
/***
*
* @param listener
* @return
*/
public boolean registerListener(BDLocationListener listener){
boolean isSuccess = false;
if(listener != null){
client.registerLocationListener(listener);
isSuccess = true;
}
return isSuccess;
}
public void unregisterListener(BDLocationListener listener){
if(listener != null){
client.unRegisterLocationListener(listener);
}
}
/***
*
* @param option
* @return isSuccessSetOption
*/
public boolean setLocationOption(LocationClientOption option){
boolean isSuccess = false;
if(option != null){
if(client.isStarted())
client.stop();
DIYoption = option;
client.setLocOption(option);
}
return isSuccess;
}
public LocationClientOption getOption(){
return DIYoption;
}
/***
*
* @return DefaultLocationClientOption
*/
public LocationClientOption getDefaultLocationClientOption(){
if(mOption == null){
mOption = new LocationClientOption();
mOption.setLocationMode(LocationMode.Hight_Accuracy);//可选,默认高精度,设置定位模式,高精度,低功耗,仅设备
mOption.setCoorType("bd09ll");//可选,默认gcj02,设置返回的定位结果坐标系,如果配合百度地图使用,建议设置为bd09ll;
mOption.setScanSpan(3000);//可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的
mOption.setIsNeedAddress(true);//可选,设置是否需要地址信息,默认不需要
mOption.setIsNeedLocationDescribe(true);//可选,设置是否需要地址描述
mOption.setNeedDeviceDirect(false);//可选,设置是否需要设备方向结果
mOption.setLocationNotify(false);//可选,默认false,设置是否当gps有效时按照1S1次频率输出GPS结果
mOption.setIgnoreKillProcess(true);//可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死
mOption.setIsNeedLocationDescribe(true);//可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近”
mOption.setIsNeedLocationPoiList(true);//可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到
mOption.SetIgnoreCacheException(false);//可选,默认false,设置是否收集CRASH信息,默认收集
}
return mOption;
}
public void start(){
synchronized (objLock) {
if(client != null && !client.isStarted()){
client.start();
}
}
}
public void stop(){
synchronized (objLock) {
if(client != null && client.isStarted()){
client.stop();
}
}
}
}
在application中添加:
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" >
<intent-filter>
<action android:name="com.baidu.location.service_v2.2" >
</action>
</intent-filter>
</service>
4. 添加权限:
<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" />
5. 布局文件中添加:
<com.baidu.mapapi.map.MapView
android:id="@+id/bmapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true" />
6. MainActivity.java
public class MainActivity extends AppCompatActivity {
private MapView mapView = null;
private BaiduMap baiduMap;
private LocationService locService;
private LinkedList<LocationEntity> locationList = new LinkedList<LocationEntity>(); // 存放历史定位结果的链表,最大存放当前结果的前5次定位结果
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//在使用SDK各组件之前初始化context信息,传入ApplicationContext
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_main);
mapView = (MapView) findViewById(R.id.bmapView);
baiduMap = mapView.getMap();
baiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
baiduMap.setMapStatus(MapStatusUpdateFactory.zoomTo(15));
locService = ((LocationApplication) getApplication()).locationService;
LocationClientOption mOption = locService.getDefaultLocationClientOption();
mOption.setLocationMode(LocationClientOption.LocationMode.Battery_Saving);
mOption.setCoorType("bd09ll");
locService.setLocationOption(mOption);
locService.registerListener(listener);
locService.start();
}
/***
* 定位结果回调,在此方法中处理定位结果
*/
BDLocationListener listener = new BDLocationListener() {
@Override
public void onReceiveLocation(BDLocation bdLocation) {
if (bdLocation != null && (bdLocation.getLocType() == 161 || bdLocation.getLocType() == 66)) {
Message locMsg = locHander.obtainMessage();
Bundle locData;
locData = Algorithm(bdLocation);
if (locData != null) {
locData.putParcelable("loc", bdLocation);
locMsg.setData(locData);
locHander.sendMessage(locMsg);
}
}
}
};
/***
* 接收定位结果消息,并显示在地图上
*/
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) {
LatLng point = new LatLng(location.getLatitude(), location.getLongitude());
BitmapDescriptor bitmap = null;
if (iscal == 0) {
bitmap = BitmapDescriptorFactory.fromResource(R.drawable.dingwei);
} else {
bitmap = BitmapDescriptorFactory.fromResource(R.drawable.icon_openmap_focuse_mark);
}
OverlayOptions option = new MarkerOptions().position(point).icon(bitmap);
baiduMap.addOverlay(option);
baiduMap.setMapStatus(MapStatusUpdateFactory.newLatLng(point));
}
} catch (Exception e) {
// TODO: handle exception
}
}
};
/***
* 平滑策略代码实现方法,主要通过对新定位和历史定位结果进行速度评分,
* 来判断新定位结果的抖动幅度,如果超过经验值,则判定为过大抖动,进行平滑处理,若速度过快,
* 则推测有可能是由于运动速度本身造成的,则不进行低速平滑处理
*/
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 * Utils.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;
}
//地图生命周期管理
@Override
protected void onDestroy() {
super.onDestroy();
locService.unregisterListener(listener);
locService.stop();
mapView.onDestroy();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
/**
* 封装定位结果和时间的实体类
*/
class LocationEntity {
BDLocation location;
long time;
}
}
刚开始出现了错误:
error inflating class com.baidu.mapapi.map.mapview
这是需要在activity中添加:
SDKInitializer.initialize(getApplicationContext());
7. Utils.java
public class Utils {
public final static String CoorType_GCJ02 = "gcj02";
public final static String CoorType_BD09LL= "bd09ll";
public final static String CoorType_BD09MC= "bd09";
/***
*61 : GPS定位结果,GPS定位成功。
*62 : 无法获取有效定位依据,定位失败,请检查运营商网络或者wifi网络是否正常开启,尝试重新请求定位。
*63 : 网络异常,没有成功向服务器发起请求,请确认当前测试手机网络是否通畅,尝试重新请求定位。
*65 : 定位缓存的结果。
*66 : 离线定位结果。通过requestOfflineLocaiton调用时对应的返回结果。
*67 : 离线定位失败。通过requestOfflineLocaiton调用时对应的返回结果。
*68 : 网络连接失败时,查找本地离线定位时对应的返回结果。
*161: 网络定位结果,网络定位定位成功。
*162: 请求串密文解析失败。
*167: 服务端定位失败,请您检查是否禁用获取位置信息权限,尝试重新请求定位。
*502: key参数错误,请按照说明文档重新申请KEY。
*505: key不存在或者非法,请按照说明文档重新申请KEY。
*601: key服务被开发者自己禁用,请按照说明文档重新申请KEY。
*602: key mcode不匹配,您的ak配置过程中安全码设置有问题,请确保:sha1正确,“;”分号是英文状态;且包名是您当前运行应用的包名,请按照说明文档重新申请KEY。
*501~700:key验证失败,请按照说明文档重新申请KEY。
*/
public static float[] EARTH_WEIGHT = {0.1f,0.2f,0.4f,0.6f,0.8f}; // 推算计算权重_地球
//public static float[] MOON_WEIGHT = {0.0167f,0.033f,0.067f,0.1f,0.133f};
//public static float[] MARS_WEIGHT = {0.034f,0.068f,0.152f,0.228f,0.304f};
}