在利用高德地圖來編寫本身的APP的時候,發現了一種對定位按鍵的重寫方法,那就是利用 com.amap.api.maps2d.LocationSource 接口來重寫。html
什麼是定位按鍵呢,下圖中右上角那個就是。java
import com.amap.api.maps2d.AMap;
private AMap aMap;//地圖控制器對象
//aMap 爲地圖控制器對象
aMap.getUiSettings().setMyLocationButtonEnabled(true);//地圖的定位標誌是否可見
aMap.setMyLocationEnabled(true);//地圖定位標誌是否能夠點擊
上面的語句是設置 顯示定位按鍵,而且使其能夠被點擊的語句。
要想使activity 中 重寫 定位按鍵的 激發事件 就須要實現接口 LocationSource , 以下:
import com.amap.api.maps2d.LocationSource;
public class GetMyLocationActivity extends AppCompatActivity implements LocationSource
首先, aMap.setLocationSource(this);//設置了定位的監聽,這裏要實現LocationSource接口
這一步的操做就是說定位按鍵的監聽對象爲 this對象。
而後,須要定義一個 LocationSource 接口中的一個嵌套接口, OnLocationChangedListener
OnLocationChangedListener mListener;
而後, 實現 LocationSource 接口中的兩個方法:
@Override public void activate(OnLocationChangedListener onLocationChangedListener) { mListener = onLocationChangedListener; //aMap.moveCamera(CameraUpdateFactory.zoomTo(18));
//Toast.makeText(getApplicationContext(), "定位按鍵啓動", Toast.LENGTH_SHORT).show();
} @Override public void deactivate() { mListener = null; }
上面的兩個實現的接口中的方法是一對, activate 是定位按鍵點擊時的觸發事件, 將傳入的對象 onLocationChangedListener 賦給類屬性 mListener , 該語句的意思是 使類屬性 mListener 指向定位按鍵的監聽器對象, 也就是說兩個對象是同一塊內存的對象。android
deactivate 是指定位按鍵結束事件, 將 mListener 對象所指向的對象設置爲空,即沒有內存空間的一個對象, 該步驟至關因而一個防止出現垃圾內存的一個回收方式。git
將代碼改寫爲以下,加入調試信息:api
@Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
mListener = onLocationChangedListener;
Log.v("mlistener", ""+mListener);
//aMap.moveCamera(CameraUpdateFactory.zoomTo(18));
}
以上的調試信息是如何操做的呢?緩存
進入activity, 打印了一次,點擊定位後又顯示了一次,這兩次的結果相同,能夠看到在一個activity 的生命週期中 監聽器的對象不變。app
當activity 消亡後再次進入, 發現對象的空間改變,能夠看出在不一樣activity 生命週期中 監聽器對象 是不一樣的。ide
其中一個比較神奇的發現就是, 在進入activity的同時,activate 方法會被執行,此時並無手動點擊定位按鍵。函數
下面一個步驟是我一直沒有太想明白的一個操做,下面也只是寫一下本身的一些理解:this
定位按鍵的 激發事件 和 銷燬事件已經寫完了, 下一步則是要將 定位按鍵的監聽器對象 註冊給定位後的操做。
也就是說 點擊定位按鍵後, mListener 是被設置爲監聽位置更新的一個對象,mListener所對應的空間爲傳進來的一個對象。
那麼剩下來的操做就是將 mListener 監聽器註冊給位置更新後觸發的事件, mListener 是監聽位置更新的監聽器,mListener 所監聽的位置對象爲 amapLocation, 該對象是定位事件中所得到的定位對象。
mListener.onLocationChanged(amapLocation);
關鍵代碼以下:
public AMapLocationListener mLocationListener = new AMapLocationListener() { @Override public void onLocationChanged(AMapLocation amapLocation) { if (amapLocation != null) { if (amapLocation.getErrorCode() == 0) { Log.v("getLocationType", ""+amapLocation.getLocationType() ) ; lat = amapLocation.getLatitude(); lon = amapLocation.getLongitude(); Log.v("getAccuracy", ""+amapLocation.getAccuracy()+" 米");//獲取精度信息 Log.v("joe", "lat :-- " + lat + " lon :--" + lon); Log.v("joe", "Country : " + amapLocation.getCountry() + " province : " + amapLocation.getProvince() + " City : " + amapLocation.getCity() + " District : " + amapLocation.getDistrict()); //清空緩存位置 aMap.clear(); if( isFirstLoc ) { // 設置顯示的焦點,即當前地圖顯示爲當前位置 aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lon), 18)); //aMap.moveCamera(CameraUpdateFactory.zoomTo(18)); //aMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(lat, lon))); //點擊定位按鈕 可以將地圖的中心移動到定位點 mListener.onLocationChanged(amapLocation); isFirstLoc=false; }
最終,我的的理解是 mListener 是定位按鍵的一個監聽器, 也就是說按下了一次定位按鍵,那麼 mListener 監聽器就會被調用,
mListener 定位到如今的位置信息是使用 mListener.onLocationChanged(amapLocation) 語句來進行設置的。
mListener 在第一次進入activity 的時候被賦值, 點擊按鍵也會被在次賦值此時意義不大,能夠將代碼:
boolean isFirstLoc2=true;
@Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
mListener = onLocationChangedListener;
Toast.makeText(getApplicationContext(), "定位到個人位置", Toast.LENGTH_SHORT).show();
//aMap.moveCamera(CameraUpdateFactory.zoomTo(18));
}
修改成:
@Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
if( isFirstLoc2 ) {
mListener = onLocationChangedListener;
isFirstLoc2=false;}
Toast.makeText(getApplicationContext(), "定位到個人位置", Toast.LENGTH_SHORT).show();
//aMap.moveCamera(CameraUpdateFactory.zoomTo(18));
}
===============================================================
其中,有一個問題,很久纔想明白,
mListener.onLocationChanged(amapLocation);
amapLocation 是位置信息, 隨着時間推移 位置信息是不斷變化的, 這是否可行?
後來 發現 amapLocation 對象 是屬於 AMapLocation類的。
也就是說, amapLocation 雖然會不斷的被傳入新值, 可是其所對應的內存空間是不變的, 也就是說對象是不變的,變的是其屬性值。
完整代碼以下:
package com.joe.ditudemo.fuction; import android.graphics.BitmapFactory; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.util.Log; import com.amap.api.location.AMapLocation; import com.amap.api.location.AMapLocationClient; import com.amap.api.location.AMapLocationClientOption; import com.amap.api.location.AMapLocationListener; import com.amap.api.maps2d.AMap; import com.amap.api.maps2d.AMapOptions; import com.amap.api.maps2d.CameraUpdateFactory; import com.amap.api.maps2d.LocationSource; import com.amap.api.maps2d.MapView; import com.amap.api.maps2d.UiSettings; import com.amap.api.maps2d.model.BitmapDescriptor; import com.amap.api.maps2d.model.BitmapDescriptorFactory; import com.amap.api.maps2d.model.LatLng; import com.amap.api.maps2d.model.Marker; import com.amap.api.maps2d.model.MarkerOptions; import com.joe.ditudemo.R; import static com.amap.api.location.AMapLocationClientOption.AMapLocationMode.Hight_Accuracy; /** * Created by Joe. */ public class GetMyLocationActivity extends AppCompatActivity implements LocationSource { //聲明AMapLocationClient類對象 public AMapLocationClient mLocationClient = null; //聲明mLocationOption對象 public AMapLocationClientOption mLocationOption = null; private double lat; private double lon; private MapView mapView; private AMap aMap;//地圖控制器對象 private UiSettings mUiSettings; OnLocationChangedListener mListener; boolean isFirstLoc = true; boolean isFirstLoc2 = true; @Override public void activate(OnLocationChangedListener onLocationChangedListener) { if( isFirstLoc2 ) { mListener = onLocationChangedListener; isFirstLoc2=false;} //Toast.makeText(getApplicationContext(), "定位到個人位置", Toast.LENGTH_SHORT).show(); aMap.moveCamera(CameraUpdateFactory.zoomTo(18)); } @Override public void deactivate() { mListener = null; } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_get_mylocation); //初始化定位 mLocationClient = new AMapLocationClient(getApplicationContext()); //設置定位回調監聽 mLocationClient.setLocationListener(mLocationListener);//設置其爲定位完成後的回調函數 mapView = (MapView) findViewById(R.id.mapView); mapView.onCreate(savedInstanceState); init(); } /** * * 初始化AMap類對象 aMap 地圖控制器 */ private void init() { if (aMap == null) { aMap = mapView.getMap();//地圖控制器對象 aMap.setLocationSource(this);//設置了定位的監聽,這裏要實現LocationSource接口 mUiSettings = aMap.getUiSettings(); } //設置logo位置 mUiSettings.setLogoPosition(AMapOptions.LOGO_POSITION_BOTTOM_CENTER);//高德地圖標誌的擺放位置 mUiSettings.setZoomControlsEnabled(true);//地圖縮放控件是否可見 mUiSettings.setZoomPosition(AMapOptions.ZOOM_POSITION_RIGHT_BUTTOM);//地圖縮放控件的擺放位置 //aMap 爲地圖控制器對象 aMap.getUiSettings().setMyLocationButtonEnabled(true);//地圖的定位標誌是否可見 aMap.setMyLocationEnabled(true);//地圖定位標誌是否能夠點擊 setUpMap(); } /** * 配置定位參數 */ private void setUpMap() { //初始化定位參數 mLocationOption = new AMapLocationClientOption(); //設置定位模式爲高精度模式,Battery_Saving爲低功耗模式,Device_Sensors是僅設備模式 mLocationOption.setLocationMode(Hight_Accuracy); //設置是否返回地址信息(默認返回地址信息) mLocationOption.setNeedAddress(true); //設置是否只定位一次,默認爲false mLocationOption.setOnceLocation(false); //設置是否容許模擬位置,默認爲false,不容許模擬位置 mLocationOption.setMockEnable(false); //設置定位間隔,單位毫秒,默認爲2000ms mLocationOption.setInterval(2000); //給定位客戶端對象設置定位參數 mLocationClient.setLocationOption(mLocationOption); //啓動定位 mLocationClient.startLocation(); } public AMapLocationListener mLocationListener = new AMapLocationListener() { @Override public void onLocationChanged(AMapLocation amapLocation) { if (amapLocation != null) { if (amapLocation.getErrorCode() == 0) { Log.v("getLocationType", ""+amapLocation.getLocationType() ) ; lat = amapLocation.getLatitude(); lon = amapLocation.getLongitude(); Log.v("getAccuracy", ""+amapLocation.getAccuracy()+" 米");//獲取精度信息 Log.v("joe", "lat :-- " + lat + " lon :--" + lon); Log.v("joe", "Country : " + amapLocation.getCountry() + " province : " + amapLocation.getProvince() + " City : " + amapLocation.getCity() + " District : " + amapLocation.getDistrict()); //清空緩存位置 aMap.clear(); if( isFirstLoc ) { // 設置顯示的焦點,即當前地圖顯示爲當前位置 aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lon), 18)); //aMap.moveCamera(CameraUpdateFactory.zoomTo(18)); //aMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(lat, lon))); //點擊定位按鈕 可以將地圖的中心移動到定位點 mListener.onLocationChanged(amapLocation); isFirstLoc=false; } MarkerOptions markerOptions = new MarkerOptions(); markerOptions.position(new LatLng(lat, lon)); markerOptions.title("個人位置"); markerOptions.visible(true); BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.icon_location)); markerOptions.icon(bitmapDescriptor); markerOptions.draggable(true); Marker marker = aMap.addMarker(markerOptions); marker.showInfoWindow(); } else { //顯示錯誤信息ErrCode是錯誤碼,errInfo是錯誤信息,詳見錯誤碼錶。 Log.e("joe", "location Error, ErrCode:" + amapLocation.getErrorCode() + ", errInfo:" + amapLocation.getErrorInfo()); } } } }; /** * 從新繪製加載地圖 */ @Override protected void onResume() { super.onResume(); mapView.onResume(); } /** * 暫停地圖的繪製 */ @Override protected void onPause() { super.onPause(); mapView.onPause(); } /** * 保存地圖當前的狀態方法必須重寫 */ @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); mapView.onSaveInstanceState(outState); } /** * 銷燬地圖 */ @Override protected void onDestroy() { super.onDestroy(); mapView.onDestroy(); if (mLocationClient != null) { mLocationClient.stopLocation(); mLocationClient.onDestroy(); } mLocationClient = null; } }
參考文章: