在利用高德地图来编写自己的APP的时候,发现了一种对定位按键的重写方法,那就是利用 com.amap.api.maps2d.LocationSource 接口来重写。
什么是定位按键呢,下图中右上角那个就是。
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 指向定位按键的监听器对象, 也就是说两个对象是同一块内存的对象。
deactivate 是指定位按键结束事件, 将 mListener 对象所指向的对象设置为空,即没有内存空间的一个对象, 该步骤相当于是一个防止出现垃圾内存的一个回收方式。
将代码改写为如下,加入调试信息:
@Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
mListener = onLocationChangedListener;
Log.v("mlistener", ""+mListener);
//aMap.moveCamera(CameraUpdateFactory.zoomTo(18));
}
以上的调试信息是如何操作的呢?
进入activity, 打印了一次,点击定位后又显示了一次,这两次的结果相同,可以看到在一个activity 的生命周期中 监听器的对象不变。
当activity 消亡后再次进入, 发现对象的空间改变,可以看出在不同activity 生命周期中 监听器对象 是不同的。
其中一个比较神奇的发现就是, 在进入activity的同时,activate 方法会被执行,此时并没有手动点击定位按键。
下面一个步骤是我一直没有太想明白的一个操作,下面也只是写一下自己的一些理解:
定位按键的 激发事件 和 销毁事件已经写完了, 下一步则是要将 定位按键的监听器对象 注册给定位后的操作。
也就是说 点击定位按键后, 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
- java.lang.Object
-
- Location
-
- com.amap.api.location.AMapLocation
- 所有已实现的接口:
- java.lang.Cloneable
也就是说, 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; } }
参考文章:
https://blog.csdn.net/PenTablet/article/details/78273743
http://www.apkbus.com/blog-904057-63610.html