在利用高德地图来编写自己的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;
}
}
参考文章
http://www.apkbus.com/blog-904057-63610.html