在网上学习使用百度定位,看了很多文章和博客始终觉得很乱,而且是看的越多,逻辑越迷糊。直到看了《Android定位技术 LBS视频教程》https://www.douban.com/group/topic/80331061/才感觉总算把逻辑理清楚了。我就在这里把我的逻辑总结出来,希望能帮到需要的人,同时也方便我今后回顾。
本篇文章不再讲述如何搭建百度地图环境了,网上大把,我就不浪费时间了,本篇着重讲实现的逻辑。
实现逻辑分为四步:
1.初始化地图。2.动态添加权限。3.请求位置。4.更新地图。
逻辑最重要的部分就是第三,第四步。也是看其他文章最容易被搅晕的步骤。
下面为各个部分贴出代码:
成员变量:
private static final int REQUEST_PERMISSION = 1;//权限请求码 private static final String TAG = "MainActivity"; private ArrayList<String> permissionList = new ArrayList<>();//权限集合 private BaiduMap baiduMap;//百度地图实例 private MapView mapView;//地图控件 private LocationClient locationClient;//位置客户端 private boolean ToastFlag = true;
该项目的整体思想:
整个项目就执行这四个大的逻辑。其中,第四步更新地图是放在第三步请求位置中执行的,因为第三步需要实时的更新位置信息,所以第四步也要随第三步实时的更新地图。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //初始化SDK。SDK随App销毁而销毁 SDKInitializer.initialize(getApplicationContext()); setContentView(R.layout.activity_main); mapView = (MapView) findViewById(R.id.mapView);//管理地图周期 //初始化地图 initialMap(); //动态添加权限 initialPermission(); //请求位置 requestLocation(); //更新地图 }
PS:1.使用百度SDK,务必要在设置布局之前初始化!
2.要对地图控件mapView的生命周期进行管理,确保资源的及时释放,如下所示:
@Override protected void onResume() { super.onResume(); mapView.onResume(); } @Override protected void onPause() { super.onPause(); mapView.onPause(); } @Override protected void onDestroy() { super.onDestroy(); mapView.onDestroy(); if (locationClient != null){ locationClient.stop(); } baiduMap.setMyLocationEnabled(false); }
一、初始化地图
//--------------初始化地图 private void initialMap() { //拿到地图实例 baiduMap = mapView.getMap(); baiduMap.setMyLocationEnabled(true);//在地图上显示当前位置(小圆点) MapStatusUpdate updateZoom = MapStatusUpdateFactory.zoomTo(18f);//显示初始地图缩放大小 baiduMap.animateMapStatus(updateZoom);//更新地图状态 }
二、动态添加权限
//--------------动态添加权限 private void initialPermission() { if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){ //加入到集合中,在集合中一起请求权限 permissionList.add(Manifest.permission.ACCESS_COARSE_LOCATION); } if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){ permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION); } if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); } if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED){ permissionList.add(Manifest.permission.READ_PHONE_STATE); } if (!permissionList.isEmpty()){ //集合转数组 String[] permissions = permissionList.toArray(new String[permissionList.size()]); //请求权限 ActivityCompat.requestPermissions(MainActivity.this,permissions,REQUEST_PERMISSION); } }
上面四个权限都是危险权限,6.0以上的手机需要动态添加权限。这里也是把没有授权的权限全部加入到集合中统一授权。
//---------回调权限请求结果 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_PERMISSION){ if (grantResults.length>0){ //遍历数组结果 for (int result:grantResults){ if (result != PackageManager.PERMISSION_GRANTED){ finish(); return; } } } } }
三、请求位置(请求位置→返回数据→更新地图)
private void requestLocation() { locationClient = new LocationClient(this); locationClient.registerLocationListener(new MyLocationListener());//注册监听事件 //设置位置参数 LocationClientOption option = new LocationClientOption(); option.setCoorType("bd09ll");//设置地图类型 option.setScanSpan(5000);//设置定位刷新时间 option.setIsNeedAddress(true);//是否使用地址(可选) option.setOpenGps(true);//开启GPS;默认不开启 locationClient.setLocOption(option); locationClient.start(); }
一定要记得注册监听事件,这样当你调用start方法就会自动执行监听器内部类的onReceive方法。
位置参数只提一点,一定要记得setOpenGps开启GPS,否则即便你打开手机上的GPS也无法使用GPS定位!新手不懂这里,很容易被坑死,而且室内通常接受不到GPS信号。。。。
接下来我们就拿到了我们的位置数据,它们都封装在onReceriveLocation方法的参数bdLocation中,如下图所示,我们需要操作这些数据。在操作数据之前,我们需要明确一点,我们最终目的是要更新地图,更新地图我们需要的两个核心方法是:1.把数据和地图绑定起来:baiduMap.setMyLocationData(data); 2.动态更新地图:baiduMap.animateMapStatus(update);
因此,我们需要准备参数MyLocationData和参数MapStatusUpdate。
//-------------监听器内部类 private class MyLocationListener extends BDAbstractLocationListener { @Override public void onReceiveLocation(BDLocation bdLocation) { Log.d(TAG, "纬度: " + bdLocation.getLatitude()); Log.d(TAG, "经度: " + bdLocation.getLongitude()); //封装数据 MyLocationData.Builder builder = new MyLocationData.Builder(); MyLocationData data = builder.direction(100) .latitude(bdLocation.getLatitude()) .longitude(bdLocation.getLongitude()) .build(); //更新地图 updateMap(data); //第一次打开地图,弹出Toast提示当前地址 if (ToastFlag){ ToastFlag = false; Toast.makeText(MainActivity.this,bdLocation.getAddrStr(), Toast.LENGTH_LONG).show(); } } }
首先我们位置信息全部封装到了MyLocationData类中,然后执行我们的第四步更新地图操作。
四、更新地图
//-------------------更新地图 private void updateMap(MyLocationData data) { //地图绑定数据 baiduMap.setMyLocationData(data); LatLng latLng = new LatLng(data.latitude, data.longitude);//经纬度实例 MapStatusUpdate updateLatLng = MapStatusUpdateFactory.newLatLng(latLng);//地图状态更新的实例 baiduMap.animateMapStatus(updateLatLng);//动态更新地图 }
绑定数据就用我们传过来的data即可。
动态更新地图,我们主要就是更新经纬度,缺什么我们就给它什么。需要一个地图状态更新的实例,好,我们就通过静态工厂类创建一个实例,创建地图状态更新实例时需要用到经纬度的实例,我们也给它准备一个经纬度的实例。
五、总结
至此我们的定位就大功告成了,最后我贴出整个程序的缩略码,方便大家回顾整个程序的逻辑结构:
public class MainActivity extends AppCompatActivity { private static final int REQUEST_PERMISSION = 1;//权限请求码 private static final String TAG = "MainActivity"; private ArrayList<String> permissionList = new ArrayList<>();//权限集合 private BaiduMap baiduMap;//百度地图实例 private MapView mapView;//地图控件 private LocationClient locationClient;//位置客户端 private boolean ToastFlag = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //初始化SDK。SDK随App销毁而销毁 SDKInitializer.initialize(getApplicationContext()); setContentView(R.layout.activity_main); mapView = (MapView) findViewById(R.id.mapView);//管理地图周期 //初始化地图 initialMap(); //动态添加权限 initialPermission(); //请求位置 requestLocation(); //更新地图 } //--------------初始化地图 private void initialMap() { //拿到地图实例 baiduMap = mapView.getMap(); baiduMap.setMyLocationEnabled(true);//在地图上显示当前位置(小圆点) MapStatusUpdate updateZoom = MapStatusUpdateFactory.zoomTo(18f); baiduMap.animateMapStatus(updateZoom); } //-------------------更新地图 private void updateMap(MyLocationData data) { //地图绑定数据 baiduMap.setMyLocationData(data); LatLng latLng = new LatLng(data.latitude, data.longitude);//经纬度实例 MapStatusUpdate updateLatLng = MapStatusUpdateFactory.newLatLng(latLng);//地图状态更新的实例 baiduMap.animateMapStatus(updateLatLng);//动态更新地图 } //----------------请求位置 private void requestLocation() { locationClient = new LocationClient(this); locationClient.registerLocationListener(new MyLocationListener());//注册监听事件 //设置位置参数 LocationClientOption option = new LocationClientOption(); option.setCoorType("bd09ll");//设置地图类型 option.setScanSpan(5000);//设置定位刷新时间 option.setIsNeedAddress(true);//是否使用地址(可选) option.setOpenGps(true);//开启GPS;默认不开启 locationClient.setLocOption(option); locationClient.start(); } //--------------动态添加权限 private void initialPermission() { if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){ //加入到集合中,在集合中一起请求权限 permissionList.add(Manifest.permission.ACCESS_COARSE_LOCATION); } if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){ permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION); } if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); } if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED){ permissionList.add(Manifest.permission.READ_PHONE_STATE); } if (!permissionList.isEmpty()){ //集合转数组 String[] permissions = permissionList.toArray(new String[permissionList.size()]); //请求权限 ActivityCompat.requestPermissions(MainActivity.this,permissions,REQUEST_PERMISSION); } } //---------回调权限请求结果 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_PERMISSION){ if (grantResults.length>0){ //遍历数组结果 for (int result:grantResults){ if (result != PackageManager.PERMISSION_GRANTED){ finish(); return; } } } } } @Override protected void onResume() { super.onResume(); mapView.onResume(); } @Override protected void onPause() { super.onPause(); mapView.onPause(); } @Override protected void onDestroy() { super.onDestroy(); mapView.onDestroy(); if (locationClient != null){ locationClient.stop(); } baiduMap.setMyLocationEnabled(false); } //-------------监听器内部类 private class MyLocationListener extends BDAbstractLocationListener { @Override public void onReceiveLocation(BDLocation bdLocation) { Log.d(TAG, "纬度: " + bdLocation.getLatitude()); Log.d(TAG, "经度: " + bdLocation.getLongitude()); //封装数据 MyLocationData.Builder builder = new MyLocationData.Builder(); MyLocationData data = builder.direction(100) .latitude(bdLocation.getLatitude()) .longitude(bdLocation.getLongitude()) .build(); //更新地图 updateMap(data); //第一次打开地图,弹出Toast提示当前地址 if (ToastFlag){ ToastFlag = false; Toast.makeText(MainActivity.this,bdLocation.getAddrStr(), Toast.LENGTH_LONG).show(); } } } }