2

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

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

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

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

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

到清单,这导致应用程序在首次运行时请求许可。然后,我的设备设置将应用程序显示为允许省电例外。

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

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");
}

}

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

该应用程序仍然可以正常工作,并且 onLocationChanged 方法仍然每 20 秒运行一次,如果我允许我的应用程序关闭其所有前台活动并仅运行上面的后台服务,只要另一个(完全不相关的)应用程序调用 GPS位置是开放和可见的。

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

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

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

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

谁能比我更了解这一点(可能不比我更好地理解它!)请帮忙?

4

2 回答 2

1

从 Android marshmallow google 开始引入一种新的电池优化方式,比如

  1. 打盹模式
  2. 应用待机模式

您可以通过Doze 和 Stand by Mode了解更多关于它们的信息, 并且这些 概念在 Android Oreo 之前一直存在争议。当谷歌宣布 android Oreo 时,他们严重依赖电池优化方式,他们引入了新的 API 来处理后台操作,如工作管理器和作业调度程序,但他们也进入打瞌睡和待机模式。并在打盹模式维护窗口中工作。
经过长时间的搜索和练习每 20 秒跟踪用户位置的最佳方法您需要使用粘性前台通知启动前台服务。这种方式不会因打瞌睡或待机模式而终止,它会根据间隔。这是对服务的解释以及启动前台服务的示例

于 2018-09-04T15:23:24.540 回答
1

适用的待机/打瞌睡文件

列入白名单的应用可以在打盹和应用待机期间使用网络并保持部分唤醒锁。但是,其他限制仍然适用于列入白名单的应用程序,就像它们对其他应用程序一样。例如,白名单应用的作业和同步被延迟(在 API 级别 23 及以下),并且其常规 AlarmManager 警报不会触发。

看来您的用例属于“其他限制仍然适用”。

您的应用程序在不活跃使用时会耗尽电池电量,这正是 App Standby 和 Doze 旨在抵消的行为。

于 2018-09-04T18:18:20.957 回答