使用Google Play服务位置在Android中唤醒过多的警报管理器

poi*_*rez 26 memory android location google-play-services

我在Google Play Console上收到Android Vital的性能报告,内容涉及过多的Alarm Manager唤醒:

https://developer.android.com/topic/performance/vitals/wakeup.html

我使用Google Play服务中的Location API来请求在后台进行位置更新.在报告中,它显示唤醒唤醒过多是由LocationListener的com.google.android.location.ALARM_WAKEUP_LOCATOR引起的.

导致警报的代码段下方:

private synchronized void buildGoogleApiClient() {
    mGoogleApiClient = new GoogleApiClient.Builder(context)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();
    mGoogleApiClient.connect();
}

/**
 * Runs when a GoogleApiClient object successfully connects.
 */
@Override
public void onConnected(Bundle connectionHint) {
    try {
        // Set location request
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(5 * 60000);
        mLocationRequest.setFastestInterval(60000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        mLocationRequest.setMaxWaitTime(30 * 60000);

        // Create a pending intent to listening on location service when the update become available
        Intent mIntent = new Intent(context, LocationReceiver.class);
        mIntent.setAction(LocationReceiver.LOCATION_EXTRA);
        mPendingIntent = PendingIntent.getBroadcast(context, 42, mIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        // Permission check before launching location services
        if (ContextCompat.checkSelfPermission(context,
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mPendingIntent);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
Run Code Online (Sandbox Code Playgroud)

此警报唤醒是否与Google Play服务中的Location API相关联?

有谁知道如何解决这个问题?

Yve*_*omb 30

谷歌定位API

这是com.google.android.location.ALARM_WAKEUP_LOCATOR每隔60秒唤醒设备并使其保持唤醒状态长达15秒的问题,导致严重的电池排水问题.

已经修复了通过外部应用程序使用手机并教授用户如何实际撤销应用程序的权限.

解决方案

以下提供了减少应用程序电池使用情况的工具.

为应用程序提供定制解决方案是不可能的,因为解决方案取决于应用程序的用例和业务逻辑以及您希望通过位置更新实现的成本效益分析.

时间间隔

电池性能问题就不足为奇了.从以下设置:

mLocationRequest.setInterval(5 * 60000);
mLocationRequest.setFastestInterval(60000);
mLocationRequest.setMaxWaitTime(30 * 60000);
Run Code Online (Sandbox Code Playgroud)

您的间隔设置为每5分钟更新一次(5*60000毫秒).那是一天24小时.如果每5分钟成功更新一次:每天12次/小时= = 288次.

最快间隔设置为1分钟(60000).虽然这是可用的,因为位置可以在设备的其他位置访问,但它仍会在您的应用中使用电源).

maxwaittime只有30分钟.这意味着该设备最多只能被唤醒并每天至少轮询48次.

增加这些时间.

setMaxWaitTime ...这可以消耗更少的电池并提供更准确的位置,具体取决于设备的硬件功能.如果您不需要立即交付位置,则应将此值设置为尽可能大,以满足您的需求....

在Android 8中,Google将请求数量限制为每小时只有几个.考虑将此作为设置请求间隔的指南.

限制更新次数

可以限制特定时间范围内的更新次数.通过在使用更新次数后主动取消位置请求或者在请求上设置到期时.通过这种方式,应用程序可以通过在应用程序中的某个触发器上创建请求并进行仔细管理来进行管理,从而使其不会无休止地继续.创建流程很困难,因为我不知道应用程序的用例.

setNumUpdates(int numUpdates)

默认情况下,位置会不断更新,直到明确删除请求为止,但您可以选择请求一定数量的更新.例如,如果您的应用程序只需要一个新的位置,那么在将请求传递给位置客户端之前,请使用值1调用此方法.

停止位置更新

另一种选择是在不需要时管理停止位置更新.这些链接提供了在活动失去焦点时调用此函数的示例,但是可以在应用程序中实现,满足某些要求(在您的业务逻辑中)或者甚至通过让用户在应用程序内打开和关闭它本身.

电池优化

确保您的应用不会忽略电池优化.

移位

另外,管理 setSmallestDisplacement(float smallestDisplacementMeters)将有助于微调应用程序,具体取决于业务逻辑.

在更新的问题之前写了以下内容.

开发人员和用户可以多久设置一次应用更新.该时间间隔优先级.

对于开发人员.

例如,您可以在发出位置请求时设置这些:

protected void createLocationRequest() {
    LocationRequest mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(10000);
    mLocationRequest.setFastestInterval(5000);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
}
Run Code Online (Sandbox Code Playgroud)

PRIORITY_NO_POWER还有一个设置,这意味着应用只会在用户要求时获取更新.

对于用户.

您需要提示用户更改位置设置

task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
    @Override
    public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
        // All location settings are satisfied. The client can initialize
        // location requests here.
        // ...
    }
});

task.addOnFailureListener(this, new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception e) {
        int statusCode = ((ApiException) e).getStatusCode();
        switch (statusCode) {
            case CommonStatusCodes.RESOLUTION_REQUIRED:
                // Location settings are not satisfied, but this can be fixed
                // by showing the user a dialog.
                try {
                    // Show the dialog by calling startResolutionForResult(),
                    // and check the result in onActivityResult().
                    ResolvableApiException resolvable = (ResolvableApiException) e;
                    resolvable.startResolutionForResult(MainActivity.this,
                            REQUEST_CHECK_SETTINGS);
                } catch (IntentSender.SendIntentException sendEx) {
                    // Ignore the error.
                }
                break;
            case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                // Location settings are not satisfied. However, we have no way
                // to fix the settings so we won't show the dialog.
                break;
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

管理用户设置的更改,请使用位置回调.

... 除了位置更新之外,您还可以使用新的LocationCallback类代替现有的 LocationListener来接收LocationAvailability更新,只要设置可能已更改,就会给您一个简单的回调,这将影响当前的LocationRequests集.

Google 在Android 8中解决了此问题.

为了降低功耗,Android 8.0(API级别26)限制了后台应用程序检索用户当前位置的频率.应用每小时只能收到几次位置更新.

注意:这些限制适用于运行Android 8.0(API级别26)或更高版本的设备上使用的所有应用,无论应用的目标SDK版本如何.


如果使用警报管理器.

这可能与警报管理器有关.

这不是一个简单的修复,最终你需要重写你如何安排更新.

  1. 为了至少减慢问题,您需要调试代码并查找Alarm Manager调用或创建计划的任何实例并减少间隔.

  2. 之后,您将需要重写应用程序的整个位置更新计划部分.

解决问题

确定应用程序中您安排唤醒警报的位置,并降低触发警报的频率.以下是一些提示:

  • 查找对AlarmManager中包含RTC_WAKEUP或ELAPSED_REALTIME_WAKEUP标志的各种set()方法的调用.
  • 我们建议您在警报的标签名称中包含您的包裹,类别或方法名称,以便您可以轻松识别源中设置警报的位置.以下是一些其他提示:
    • 在名称中留下任何个人识别信息(PII),例如电子邮件地址.否则,设备会记录_UNKNOWN而不是警报名称.
    • 不要以编程方式获取类或方法名称,例如通过调用getName(),因为它可能会被Proguard混淆.而是使用硬编码的字符串.
    • 请勿向警报标签添加计数器或唯一标识符.系统将无法聚合以这种方式设置的警报,因为它们都具有唯一标识符.

解决问题后,通过运行以下ADB命令验证唤醒警报是否按预期工作:

adb shell dumpsys警报

此命令提供有关设备上警报系统服务状态的信息.有关更多信息,请参阅dumpsys.

如果您对上述任何内容有特殊问题,则需要使用mcve发布另一个问题.

要改进应用程序,它将涉及重写代码,如最佳实践中所述.如果手机处于睡眠状态,请勿使用警报管理器来安排后台任务,并将位置视为后台任务.另外你说它是一个后台任务.使用JobSchedulerFirebase JobDispatcher.

如果警报管理器是更好的选择(它不在这里),重要的是在这里有一个好的读取调度重复警报,但你需要了解权衡

设计不良的警报可能会导致电池耗尽并对服务器造成很大负担.