Android中带有Google Play服务位置的闹钟管理器过度唤醒 [英] Excessive Alarm Manager wakeups in android with Google Play Services Location

查看:343
本文介绍了Android中带有Google Play服务位置的闹钟管理器过度唤醒的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我收到了Google Play控制台上的Android Vital关于Excessive Alarm Manager唤醒的性能报告:

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



我使用Google Play服务的位置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();
}

/ **
*当GoogleApiClient对象成功连接时运行。
* /
@Override
public void onConnected(Bundle connectionHint){
try {
//设置位置请求
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(5 * 60000);
mLocationRequest.setFastestInterval(60000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
mLocationRequest.setMaxWaitTime(30 * 60000);

//当更新变为可用时,创建一个等待定位服务的侦听
Intent mIntent = new Intent(context,LocationReceiver.class);
mIntent.setAction(LocationReceiver.LOCATION_EXTRA);
mPendingIntent = PendingIntent.getBroadcast(context,42,mIntent,PendingIntent.FLAG_CANCEL_CURRENT);
//启动位置服务之前的权限检查
if(ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED){
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,mLocationRequest,mPendingIntent);
} catch(Exception e){
e.printStackTrace();






此警报唤醒是否与谷歌的Location API相关联播放服务?



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

解决方案

< h2> Google Location api

这是 com.google.android.location.ALARM_WAKEUP_LOCATOR 每60秒钟启动一次设备并保持15秒钟的清醒状态,从而导致严重的电池排水问题。

手机使用修正通过外部的应用程序,并教导用户如何实际撤消权限一个应用程序。

解决方案



以下提供了一些工具来减少应用程序的电池使用情况。 / p>

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



时间间隔



电池性能问题并不令人惊讶。从以下设置:

  mLocationRequest.setInterval(5 * 60000); 
mLocationRequest.setFastestInterval(60000);
mLocationRequest.setMaxWaitTime(30 * 60000);

您的间隔设置为每5分钟更新一次(5 * 60000ms)。这是一天24小时。如果每5分钟更新一次:12次/小时,每天288次。

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



maxwaittime只有30分钟。这意味着至多该设备将被唤醒并每天至少调查48次。



增加这些时间 b
$ b


setMaxWaitTime ...这样可以消耗更少的电量并提供更准确的位置,
取决于该设备的硬件功能。如果您不需要
的即时位置递送,则应将此
值设置为尽可能大以满足您的需求。 ...

在Android 8中,Google只将请求数量限制在每小时几次。请考虑以此作为设置请求间隔的准则。



限制更新次数



更新次数在一定的时间范围内可以受到限制。通过一旦更新数量已被使用或者设置到期。通过这种方式,应用程序可以通过在应用程序内的某个触发器上创建请求进行管理,并进行小心管理,以使其不会无休止地继续。创建流程很困难,因为我不知道应用程序的用例。



setNumUpdates(int numUpdates)


默认位置会不断更新,直到请求被
显式删除,但是您可以选择请求一组
更新。例如,如果您的应用程序只需要一个新的
位置,则在将
请求传递给位置客户端之前,调用此方法的值为1。




停止位置更新



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

电池优化



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

位移



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



更新的问题。



开发者和用户都可以设置应用更新的频率。 间隔和< href =https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest#setPriority(int) =noreferrer>优先级。



对于开发人员 a>。



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

  protected void createLocationRequest(){
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10000);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
}

还有一个设置 PRIORITY_NO_POWER ,这意味着该应用只会在用户请求时才会更新。

对于用户。



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

  task.addOnSuccessListener(this,new OnSuccessListener< LocationSettingsResponse>(){
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse){
//所有位置设置为满意。客户可以在这里初始化
//位置请求。
// ...
}
});

task.addOnFailureListener(this,new OnFailureListener(){
@Override
public void onFailure(@NonNull Exception e){
int statusCode =((ApiException) e).getStatusCode();
switch(statusCode){
case CommonStatusCodes.RESOLUTION_REQUIRED:
//位置设置不满足,但可以通过显示固定
// //
//通过调用startResolutionForResult(),
来显示对话框,并检查onActivityResult()中的结果
ResolvableApiException resolvable =(ResolvableApiException )e;
resolvable.startResolutionForResult(MainActivity.this,
REQUEST_CHECK_SETTINGS);
} catch(IntentSender.SendIntentException sendEx){
//忽略错误
}
打破;
案例LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
//位置设置不满意。但是,我们没有办法
//来修复设置,所以我们不会显示对话框。
休息;
}
}
});

管理用户设置中的更改使用位置回拨功能。


...您可以使用新的 LocationCallback 类取代现有的
LocationListener 接收 LocationAvailability 的更新广告将
分配给位置更新,只要设置
可能发生变化,就会给您一个简单的回调,这会影响当前的
LocationRequests集合。




Google 已解决 Android 8中的这个问题。




为了降低功耗,Android 8.0(API等级26)
限制了经常后台应用程序可以检索用户当前的
位置。注意:这些限制适用于运行设备的所有应用程序,这些应用程序只能在每个
小时内接收位置更新。 b
Android 8.0(API等级26)或更高,无论应用程序的目标
SDK版本为何。








如果使用Alarm Manager。



这可能与闹钟管理器



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


  1. 至少减缓问题的发生您需要调试代码并查找Alarm Manager调用的任何实例,或创建计划并缩短间隔。

  2. >

    修复问题


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



    • 寻找对各种 set ()方法在 AlarmManager 中包含 RTC_WAKEUP 或ELAPSED_REALTIME_WAKEUP标志。

    • 我们建议您在报警标签名称中包括您的包裹,班级或方法名称,以便您可以轻松识别设置了报警的
      源位置。以下是一些额外提示:


      • 不要在名称中留下任何个人识别信息(PII),例如电子邮件地址。否则,设备会记录_UNKNOWN
        而不是闹钟名称。 不要以编程方式获取类或方法名称,例如通过调用 getName(),因为它可能会被Proguard混淆。
        改为使用硬编码的字符串。
      • 不要在计算机报警标签中添加计数器或唯一标识符。系统将无法聚合设置为
        的警报,因为它们都具有唯一的标识符。




    解决问题后,通过运行以下


    adb shell dumpsys警报


    该命令提供有关设备上报警系统
    服务状态的信息。有关详情,请参阅
    垃圾箱


    如果您遇到以上任何问题,则需要使用 mcve



    为改进应用程序,它将涉及重写最佳实践不要使用闹钟管理器安排后台任务,如果手机处于睡眠状态,则位置将被视为后台任务。另外你说这是一个后台任务。使用 JobScheduler Firebase JobDispatcher



    如果警报管理器是更好的选择( ),在这里阅读很有必要调度重复警报,但您需要 了解权衡
    $ b


    设计糟糕的警报可能会导致电池耗尽并给服务器带来很大负担。



    I received an performance report from Android Vital on Google Play Console about Excessive Alarm Manager wakeups:

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

    I use Location API from Google Play Services to request for location updates in the background. On the report it show that the excessive wake up wakeups was caused by com.google.android.location.ALARM_WAKEUP_LOCATOR from LocationListener.

    Below the code snippet which causes the alarms:

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

    Is this alarm wakeup linked to the Location API from google play services?

    Is anyone know how to fix this issue?

    解决方案

    The Google Location api

    This is an issue with the com.google.android.location.ALARM_WAKEUP_LOCATOR waking up devices every 60 seconds and keeping them awake for up to 15 seconds, causing major battery drainage issues.

    There's been fixes for phone uses via external apps and teaching users how to actually revoke permission for an app.

    The Solution

    The following provides the tools to reduce the battery usage of the app.

    It's impossible to provide a customised solution for the app, as the solution depends upon the use case and business logic of the app and a cost benefit analysis of what you wish to achieve with the location updates.

    Time intervals

    It's no surprise there's battery performance issues. From the following settings:

    mLocationRequest.setInterval(5 * 60000);
    mLocationRequest.setFastestInterval(60000);
    mLocationRequest.setMaxWaitTime(30 * 60000);
    

    Your interval is set to update every 5 minutes (5 * 60000ms). That's 24 hours a day. If this updates successfully every 5 minutes: 12 times/hour == 288 times per day.

    The fastest interval being set at 1 minute (60000). Although that is available because location is accessed elsewhere on the device, it will still use power in your app).

    The maxwaittime is only 30 minutes. Which means at best the device will be woken up and polled a minimum of 48 times per day.

    Increase these times.

    setMaxWaitTime ... This can consume less battery and give more accurate locations, depending on the device's hardware capabilities. You should set this value to be as large as possible for your needs if you don't need immediate location delivery. ...

    In Android 8 Google has limited the number of requests to only a few per hour. Consider using this as a guideline in setting intervals for requests.

    Limiting number of updates

    The number of updates within a certain time frame can be limited. By either actively cancelling the location request once the number of updates have been used or setting an expiration on the request. This way the app can be managing by creating a request on some trigger within the app and carefully managed so that it doesn't continue endlessly. It's difficult to create a flow, as I don't know the use case for the app.

    setNumUpdates (int numUpdates)

    By default locations are continuously updated until the request is explicitly removed, however you can optionally request a set number of updates. For example, if your application only needs a single fresh location, then call this method with a value of 1 before passing the request to the location client.

    Stop location updates

    Another option is to manage stop locations updates when they are not required. The links gives examples of calling this when an activity loses focus, however it could be implemented within the app, when certain requirements are met (that's within your business logic) or even by giving the user to turn it on and off from within the app itself.

    Battery optimisation

    Ensure your app is not ignoring battery optimizations.

    Displacement

    Also managing setSmallestDisplacement (float smallestDisplacementMeters) will help to fine tune the app, depending on the business logic.

    the following was written before the updated question.

    How often the app updates can be set by both the developer and the user. The intervals and priorities.

    For the developer.

    You can set these when making a location request for example:

    protected void createLocationRequest() {
        LocationRequest mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(10000);
        mLocationRequest.setFastestInterval(5000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
    }
    

    There is also a setting for PRIORITY_NO_POWER, which means the app will only get updates when the user asks for them.

    For the user.

    You will need to Prompt the User to Change Location Settings

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

    To manage changes in user setting use a location call back.

    ... you can use the new LocationCallback class in place of your existing LocationListener to receive LocationAvailability updates in addition to location updates, giving you a simple callback whenever settings might have changed which will affect the current set of LocationRequests.

    Google has addressed this issue in Android 8.

    In an effort to reduce power consumption, Android 8.0 (API level 26) limits how frequently background apps can retrieve the user's current location. Apps can receive location updates only a few times each hour.

    Note: These limitations apply to all apps used on devices running Android 8.0 (API level 26) or higher, regardless of an app's target SDK version.


    If using the Alarm Manager.

    This can be related to the Alarm Manager.

    It's not a simple fix, ultimately you'll need to rewrite how you are scheduling your updates.

    1. To at least slow down the problem you'll need to debug your code and find any instances where the Alarm Manager calls or creates schedules and reduce the intervals.

    2. After that you will need to rewrite the entire location update scheduling part of the app.

    Fix the Problem

    Identify the places in your app where you schedule wakeup alarms and reduce the frequency that those alarms are triggered. Here are some tips:

    • Look for calls to the various set() methods in AlarmManager that include either the RTC_WAKEUP or ELAPSED_REALTIME_WAKEUP flag.
    • We recommend including your package, class, or method name in your alarm's tag name so that you can easily identify the location in your source where the alarm was set. Here are some additional tips:
      • Leave out any personally identifying information (PII) in the name, such as an email address. Otherwise, the device logs _UNKNOWN instead of the alarm name.
      • Don't get the class or method name programmatically, for example by calling getName(), because it could get obfuscated by Proguard. Instead use a hard-coded string.
      • Don't add a counter or unique identifiers to alarm tags. The system will not be able to aggregate alarms that are set that way because they all have unique identifiers.

    After fixing the problem, verify that your wakeup alarms are working as expected by running the following ADB command:

    adb shell dumpsys alarm

    This command provides information about the status of the alarm system service on the device. For more information, see dumpsys.

    If you have particular issues with any of the above, you'll need to post another question with an mcve.

    To improve the app, it would involve rewriting the code as mentioned here in Best Practices. Don't use the alarm manager to schedule background tasks, and location would be considered a background task, if the phone is asleep. Plus you say it's a background task. Use JobScheduler or Firebase JobDispatcher.

    If the Alarm Manager is the better choice (which it's not here) it's important to have a good read here Scheduling Repeating Alarms, but you need to Understand the Trade-offs

    A poorly designed alarm can cause battery drain and put a significant load on servers.

    这篇关于Android中带有Google Play服务位置的闹钟管理器过度唤醒的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆