Google Play Services for Android中的退避位置请求

Google Play Services for Android中的退避位置请求,android,google-location-services,Android,Google Location Services,我正在使用android的Google play服务定期请求用户的位置 我创建了一个后台服务,它请求用户的位置并将该位置保存在设备内部存储器中 到目前为止一切正常。 现在,我想实现一种退避机制:用户越是静止,位置更新的频率就应该越低(反之亦然) 问题:当我调用方法requestLocationUpdates(GoogleAppClient、LocationRequest、LocationListener listener、Looper Looper)时,会立即发出位置请求(不考虑Location

我正在使用android的Google play服务定期请求用户的位置

我创建了一个后台服务,它请求用户的位置并将该位置保存在设备内部存储器中

到目前为止一切正常。

现在,我想实现一种退避机制:用户越是静止,位置更新的频率就应该越低(反之亦然)

问题:当我调用方法requestLocationUpdates(GoogleAppClient、LocationRequest、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 + "]");
    }

}

这就是它的工作原理。如果您不想立即(或在实践中尽快)更新第一个位置然后不要立即请求新的更新。谢谢@MarkusKauppinen,我正在考虑使用alarmmanager,每X分钟请求一次最新的known位置。在这种情况下,我可以更好地控制何时请求位置更新。请记住“最后一个已知位置”除非设备上的某个应用程序请求位置更新,否则不会更新。当然,如果其他应用程序这样做(无论如何,你会得到结果),这就足够了,但你无法控制它们。