Android:百度地圖的簡單定位開發
在網上學習使用百度定位,看了很多文章和部落格始終覺得很亂,而且是看的越多,邏輯越迷糊。直到看了《Android定位技術 LBS視訊教程》https://www.douban.com/group/topic/80331061/才感覺總算把邏輯理清楚了。我就在這裡把我的邏輯總結出來,希望能幫到需要的人,同時也方便我今後回顧。
本篇文章不再講述如何搭建百度地圖環境了,網上大把,我就不浪費時間了,本篇著重講實現的邏輯。
實現邏輯分為四步:
1.初始化地圖。2.動態新增許可權。3.請求位置。4.更新地圖。
邏輯最重要的部分就是第三,第四步。也是看其他文章最容易被攪暈的步驟。
下面為各個部分貼出程式碼:
成員變數:
private static final intREQUEST_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(); } } } }