android - 当应用程序处于后台时如何保持 GPS 接收器位置更新(Google Play 服务位置 API)

标签 android gps background-service android-doze power-saving

抱歉,这是一个很长的问题,但我希望你们中的一位专家可以帮助一个正在悄悄发疯的新手!!

我有一个 Android 应用程序,它使用后台服务每 20 秒获取一次 GPS 修复(使用 Google Play 服务)。它将纬度和经度与列表中的纬度和经度进行比较,如果找到匹配项,则会向接收器发送广播,触发前台 Activity 以提醒用户。

我使用后台服务,因为用户警报之间通常有 2 到 20 分钟的间隔,并且在这之间没有用户交互。该应用程序使用前台 Activity 供用户选择他想要的选项,但随后关闭所有前台 Activity ,只留下后台 Activity 运行。

这在我的旧设备上的 Android 4.3 上运行良好,但我现在正在更新它在 Android 8 (Oreo) 上运行(在 Sony Xperia XZ1Compact 上进行测试)。我已经添加了

<uses-permission 
android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/

到 list ,这导致应用程序在首次运行时请求许可。然后,我的设备设置将应用程序显示为允许节能异常(exception)。

后台服务的代码(抱歉,代码有点多,但我已经将其全部包含在内,以防相关!)如下

package com.barney.trackgps;

import android.Manifest;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;

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;



public class ApiTrackService extends Service implements
    GoogleApiClient.ConnectionCallbacks, 
GoogleApiClient.OnConnectionFailedListener,
    LocationListener {

GoogleApiClient mLocationClient;
LocationRequest mLocationRequest = new LocationRequest();
public static final String ACTION_LOCATION_BROADCAST = 
ApiTrackService.class.getName() + "LocationBroadcast";
public static final String EXTRA_LATITUDE = "extra_latitude";
public static final String EXTRA_LONGITUDE = "extra_longitude";

int interval=20; //time between fixes in seconds


@Override
public void onDestroy(){
    super.onDestroy();
    stopSelf();
}


@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.v("sTag","Got to apitrack");
    mLocationClient = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();
    mLocationRequest.setInterval(interval*1000);
    mLocationRequest.setFastestInterval(1000);
    int priority = LocationRequest.PRIORITY_HIGH_ACCURACY;
    mLocationRequest.setPriority(priority);
    mLocationClient.connect();
    return START_STICKY;
}


@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}


@Override
public void onConnected(Bundle dataBundle) {
    if (ActivityCompat.checkSelfPermission(this, 
Manifest.permission.ACCESS_FINE_LOCATION) != 
PackageManager.PERMISSION_GRANTED && 
ActivityCompat.checkSelfPermission(this, 
Manifest.permission.ACCESS_COARSE_LOCATION) != 
PackageManager.PERMISSION_GRANTED) {
        return;
    }

LocationServices.FusedLocationApi.requestLocationUpdates(mLocationClient, 
mLocationRequest, this);
}


@Override
public void onConnectionSuspended(int i) {
}


//to get the location change
@Override
public void onLocationChanged(Location location) {
    boolean locFound=false;
    Log.v("sTag","Got a fix");
        /*does stuff to compare latitude and longitude with places in a list 
        and sets locFound=true if it finds a match*/
    if (location != null) {
        GPSLog=GPSLog+"Found";
        if (locFound) {
            Log.v("sTag", "Sending broadcast");
            Intent intent = new Intent();
            intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
            intent.setAction("com.AboutMyJourney.posBroadcast");
            sendBroadcast(intent);
        }
    }
}


@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    //Log.d(TAG, "Failed to connect to Google API");
}

}

只要应用程序的前台 Activity 之一打开且可见,它就可以正常工作。使用 logcat 进行跟踪显示后台服务正在获取 GPS 修复,并且 onLocationChanged 下的代码(请参阅上面的代码)每 20 秒运行一次。

如果我允许我的应用程序关闭其所有前台 Activity 并仅运行上面的后台服务,只要另一个(完全不相关的)应用程序是调用 GPS 位置是开放且可见的。

但是,如果我的屏幕上没有任何使用 GPS 的应用程序,则 GPS 跟踪就会停止; onLocationChanged 方法不再运行,我不再获得 GPS 修复。

如果我随后打开应用程序的前台 Activity 之一,GPS 跟踪会再次启动,显示后台服务尚未终止。

我假设这与为实现省电/打瞌睡模式而进行的更改有关,但我只是没有正确理解它。然而,我能找到的所有建议似乎都表明,只要在设备白名单中允许后台服务作为异常(exception),后台服务就会继续工作,但这显然没有发生。

让后台服务工作是我的首选,因为这意味着编写新代码的工作量最少!。然而,对类似问题的一些答复建议使用带有通知的前台服务。这是否满足我的要求,即大多数时候没有可见的用户界面(可能除了通知),只提示用户每隔几分钟做某事,但同时让他或她可以自由地做其他事情?它在旧版本的 Android 中也能正常工作吗?

任何比我更理解这一点的人都可以帮忙吗(可能比我更理解它并不难!)请帮忙?

最佳答案

applicable standby/doze documentation

An app that is whitelisted can use the network and hold partial wake locks during Doze and App Standby. However, other restrictions still apply to the whitelisted app, just as they do to other apps. For example, the whitelisted app’s jobs and syncs are deferred (on API level 23 and below), and its regular AlarmManager alarms do not fire.

您的用例似乎属于“其他限制仍然适用”的范围。

您的应用程序在不活跃使用时会耗尽电池,这正是应用程序待机和打瞌睡旨在抵消的行为。

关于android - 当应用程序处于后台时如何保持 GPS 接收器位置更新(Google Play 服务位置 API),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52168945/

相关文章:

java - 如何以编程方式知道应用程序是否使用调试或导出证书签名?

java - 我可以确定 Realm 数据库文件内的实例数量吗?

Android Studio 未检测到 Kindle Fire HD 平板电脑

c# - 如何使 ExecuteAsync 异步运行

android - 在 android studio 的后台服务中调用通知监听器

android - Android 1.6 如何在现有联系人中插入联系人信息?

android如何以7位或更多位精度获取当前位置

iOS:当从设置中关闭位置服务时,我可以禁用带有设置按钮的默认警报弹出窗口吗

android - 为什么我的 phone-gap 应用无法在某些 Android 设备上找到地理定位

android - 持续在后台服务中获取位置更新