近期一个项目用到了该功能,因此进行了比较详细的研究,在这里整理一下。
首先指的一提的是,Android Q版本之后,定位权限有一个改动就是,如果是后台服务想要获取地理位置信息的话,需要申请新的权限ACCESS_BACKGROUND_LOCATION ,如果不想申请该权限进行定位的话,需要将服务切换为前台服务,如何切换的代码在github地址上,附在本文最后。
接下来进行位置监听的代码分析:
想要获取后台位置监听的话,可以直接调用LocationManager的requestLocationUpdates方法,通常来说直接调用的是:
public void requestLocationUpdates(String provider, long minTime, float minDistance,
LocationListener listener, Looper looper) {
checkProvider(provider);
checkListener(listener);
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
provider, minTime, minDistance, false);
requestLocationUpdates(request, listener, looper, null);
}
刚开始进行参数的非空校验:
private static void checkProvider(String provider) {
if (provider == null) {
throw new IllegalArgumentException("invalid provider: " + provider);
}
}
之后调用createFromDeprecatedProvider生成一个request,该部分代码很简单
public static LocationRequest createFromDeprecatedProvider(String provider, long minTime,
float minDistance, boolean singleShot) {
if (minTime < 0) minTime = 0;
if (minDistance < 0) minDistance = 0;
int quality;
if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
quality = POWER_NONE;
} else if (LocationManager.GPS_PROVIDER.equals(provider)) {
quality = ACCURACY_FINE;
} else {
quality = POWER_LOW;
}
LocationRequest request = new LocationRequest()
.setProvider(provider)
.setQuality(quality)
.setInterval(minTime)
.setFastestInterval(minTime)
.setSmallestDisplacement(minDistance);
if (singleShot) request.setNumUpdates(1);
return request;
}
创建好request调用requestLocationUpdates:
private void requestLocationUpdates(LocationRequest request, LocationListener listener,
Looper looper, PendingIntent intent) {
String packageName = mContext.getPackageName();
// wrap the listener class
ListenerTransport transport = wrapListener(listener, looper);
try {
mService.requestLocationUpdates(request, transport, intent, packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
其中wrapListener的实现如下:
private ListenerTransport wrapListener(LocationListener listener, Looper looper) {
if (listener == null) return null;
synchronized (mListeners) {
ListenerTransport transport = mListeners.get(listener);
if (transport == null) {
transport = new ListenerTransport(listener, looper);
}
mListeners.put(listener, transport);
return transport;
}
}
mListeners是维护listener的一个hashmap:
// Map from LocationListeners to their associated ListenerTransport objects
private HashMap<LocationListener,ListenerTransport> mListeners =
new HashMap<LocationListener,ListenerTransport>();
如果该listener之前未注册过的话,会生成一个新的ListenerTransport:
ListenerTransport(LocationListener listener, Looper looper) {
mListener = listener;
if (looper == null) {
mListenerHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
_handleMessage(msg);
}
};
} else {
mListenerHandler = new Handler(looper) {
@Override
public void handleMessage(Message msg) {
_handleMessage(msg);
}
};
}
}
这里会进行loop的判断,一般来说,我们不传入loop时,会生成一个指向当前线程消息队列的handler,接下来看下_handleMessage的实现:
private void _handleMessage(Message msg) {
switch (msg.what) {
case TYPE_LOCATION_CHANGED:
Location location = new Location((Location) msg.obj);
mListener.onLocationChanged(location);
break;
case TYPE_STATUS_CHANGED:
Bundle b = (Bundle) msg.obj;
String provider = b.getString("provider");
int status = b.getInt("status");
Bundle extras = b.getBundle("extras");
mListener.onStatusChanged(provider, status, extras);
break;
case TYPE_PROVIDER_ENABLED:
mListener.onProviderEnabled((String) msg