我正在使用适用于 android 的 Google Play 服务来定期请求用户的位置。
我创建了一个后台服务,它请求用户的位置并将位置保存在设备内部存储中。
到目前为止一切正常。
现在,我想实现一种退避机制:用户越静止,位置更新的频率应该越低(反之亦然)。
问题:当我调用方法 requestLocationUpdates(GoogleApiClient client, LocationRequest request, LocationListener listener, Looper looper) 时,会立即发出位置请求(不考虑 LocationRequest 对象中间隔的新值。
源代码 :
/*
* Copyright (C) 2017 app
*/
package com.app.android.location.service;
import android.Manifest;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.app.android.location.data.LocationEvent;
import com.app.android.location.provider.LocationGson;
import com.app.android.location.provider.LocationHistoryProvider;
import com.app.android.location.utils.LocationUtils;
import com.app.android.share.utils.Logger;
public class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
public static final String TAG = "LocationService";
private GoogleApiClient mGoogleApiClient;
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private LocationHistoryProvider mLocationHistoryProvider;
private LocationRequest mLocationRequest = LocationRequest.create().setInterval(LocationUtils.DEFAULT_FASTEST_INTERVAL_MILLIS).setMaxWaitTime(LocationUtils.DEFAULT_FASTEST_INTERVAL_MILLIS).setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler implements LocationListener {
ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
buildAndConnectGoogleApiClient();
}
@Override
public void onLocationChanged(final Location location) {
final LocationEvent newestLocationEvent = new LocationEvent.Builder().setLocation(location).build();
Logger.warn(TAG, "onLocationChanged() called with: location = [" + newestLocationEvent + "]");
Logger.warn(TAG, "currentInterval " + LocationUtils.getCurrentFastestInterval());
LocationUtils.getLatestLocation(mLocationHistoryProvider, new LocationUtils.LocationEventFound() {
@Override
public void onLocationEventFound(LocationEvent latestLocationEvent) {
if (latestLocationEvent != null && LocationUtils.isLocationUnchanged(latestLocationEvent, newestLocationEvent)) {
Logger.debug(TAG, "latestLocationEvent Found");
// compare the newest location to the last location that we saved
updateLocationRequests(true);
} else {
Logger.debug(TAG, "latestLocationEvent Not Found");
// if we cannot find a previous item saved, then just save this new item
mLocationHistoryProvider.addLocation(newestLocationEvent);
}
}
});
}
}
@Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
mLocationHistoryProvider = LocationGson.getInstance();
}
@Override
public void onDestroy() {
super.onDestroy();
destroyAndDisconnectGoogleApiClient();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_STICKY;
}
private void destroyAndDisconnectGoogleApiClient() {
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, mServiceHandler);
mGoogleApiClient.disconnect();
}
}
protected synchronized void buildAndConnectGoogleApiClient() {
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
if (!mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
}
private void updateLocationRequests(boolean backoff) {
if (backoff) {
long intervalMillis = Math.min(mLocationRequest.getInterval() * 2, LocationUtils.SLOWEST_INTERVAL_MILLIS);
Logger.warn(TAG, "backoff() called with: fastestIntervalMillis = [" + intervalMillis + "]");
mLocationRequest.setInterval(intervalMillis);
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mServiceHandler, mServiceLooper);
} else {
Logger.debug(TAG, "permissions for location not granted");
}
}
@Override
public void onConnected(@Nullable Bundle bundle) {
Logger.warn(TAG, "onConnected() called with: bundle = [" + bundle + "]");
updateLocationRequests(false);
}
@Override
public void onConnectionSuspended(int i) {
Logger.warn(TAG, "onConnectionSuspended() called with: i = [" + i + "]");
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult result) {
Logger.warn(TAG, "onConnectionFailed() called with: result = [" + result + "]");
}
}