Google Play Services for Android中的退避位置请求
我正在使用android的Google play服务定期请求用户的位置 我创建了一个后台服务,它请求用户的位置并将该位置保存在设备内部存储器中 到目前为止一切正常。 现在,我想实现一种退避机制:用户越是静止,位置更新的频率就应该越低(反之亦然) 问题:当我调用方法requestLocationUpdates(GoogleAppClient、LocationRequest、LocationListener listener、Looper Looper)时,会立即发出位置请求(不考虑LocationRequest对象中间隔的新值)。 源代码:Google Play Services for Android中的退避位置请求,android,google-location-services,Android,Google Location Services,我正在使用android的Google play服务定期请求用户的位置 我创建了一个后台服务,它请求用户的位置并将该位置保存在设备内部存储器中 到目前为止一切正常。 现在,我想实现一种退避机制:用户越是静止,位置更新的频率就应该越低(反之亦然) 问题:当我调用方法requestLocationUpdates(GoogleAppClient、LocationRequest、LocationListener listener、Looper Looper)时,会立即发出位置请求(不考虑Location
/*
* 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 + "]");
}
}
这就是它的工作原理。如果您不想立即(或在实践中尽快)更新第一个位置然后不要立即请求新的更新。谢谢@MarkusKauppinen,我正在考虑使用alarmmanager,每X分钟请求一次最新的known位置。在这种情况下,我可以更好地控制何时请求位置更新。请记住“最后一个已知位置”除非设备上的某个应用程序请求位置更新,否则不会更新。当然,如果其他应用程序这样做(无论如何,你会得到结果),这就足够了,但你无法控制它们。