在Android上使用Google Play服务位置过多的闹钟pipe理器唤醒

我收到了Google Play控制台上的Android Vital关于“过度闹钟pipe理器”唤醒的性能报告:

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

这个警报唤醒是从谷歌播放服务链接到位置API吗?

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

Solutions Collecting From Web of "在Android上使用Google Play服务位置过多的闹钟pipe理器唤醒"

Google位置api

这是com.google.android.location.ALARM_WAKEUP_LOCATOR每60秒钟唤醒一次设备并使它们保持醒来长达15秒的问题,从而导致严重的电池排水问题。

通过外部应用 程序修复了手机使用问题,并教导用户如何撤销应用程序的权限。

解决scheme

以下提供了减less应用程序电池使用的工具。

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

时间间隔

电池性能问题并不奇怪。 从以下设置中:

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

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

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

maxwaittime只有30分钟。 这意味着最好的设备将被唤醒和每天至less48次调查。

增加这些时间 。

setMaxWaitTime …这可以消耗更less的电池,并提供更准确的位置,具体取决于设备的硬件function。 如果您不需要即时的位置传递,则应该将此值设置为尽可能大以满足您的需求。 …

在Android 8中,Google已经将请求数量限制在每小时几个 。 考虑以此为准则来设定请求间隔。

限制更新的数量

一定时间范围内的更新次数可能会受到限制。 一旦使用了更新次数,或者在请求中设置过期时 ,通过主动取消位置请求。 这样,应用程序就可以通过在应用程序内的某个触发器上创build一个请求来进行pipe理,并进行仔细的pipe理,使其不会无休止地继续。 创buildstream程很困难,因为我不知道应用程序的用例。

setNumUpdates(int numUpdates)

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

停止位置更新

另一个选项是在不需要时pipe理停止位置更新 。 这些链接给出了一个例子,当一个活动失去焦点的时候调用它,但是当满足某些需求时(这是在你的业务逻辑中),或者甚至通过给用户打开和closures应用程序本身。

电池优化

确保您的应用程序不会忽略电池优化 。

移位

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

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

应用程序更新的频率可以由开发人员和用户设置。 间隔和优先级 。

对于开发者 。

您可以在进行位置请求时进行设置,例如:

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

要pipe理用户设置中的更改 ,请使用位置回拨。

…除了位置更新之外,您还可以使用新的LocationCallback类代替现有的LocationListener来接收LocationAvailability更新,只要设置可能发生变化,就会给您一个简单的callback,这将影响当前的一组LocationRequests。

Google 已经在Android 8中解决了这个问题。

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

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


如果使用报警pipe理器。

这可能与报警pipe理器有关 。

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

  1. 为了至less减缓问题的发生,您需要debugging代码,并findAlarm Manager调用或创build调度并减less间隔的任何实例。

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

解决问题

确定应用程序中安排唤醒警报的位置,并降低触发这些警报的频率。 这里有一些提示:

  • 在AlarmManager中寻找对各种set()方法的调用 ,包括RTC_WAKEUP或ELAPSED_REALTIME_WAKEUP标志。
  • 我们build议您在报警标签名称中包括您的包裹,class级或方法名称,以便您可以轻松识别报警源的来源位置。 这里有一些额外的提示:
    • 将姓名中的任何个人识别信息(PII)留出,例如电子邮件地址。 否则,设备将logging_UNKNOWN而不是报警名称。
    • 不要以编程方式获取类或方法名称,例如调用getName() ,因为它可能会被Proguard混淆。 而是使用硬编码的string。
    • 不要将警报标签添加计数器或唯一标识符。 系统将无法聚合以这种方式设置的警报,因为它们都具有唯一的标识符。

解决问题后,通过运行以下ADB命令validation您的唤醒警报是否正常工作:

adb shell dumpsys报警

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

如果您遇到以上任何问题,则需要使用mcve发布另一个问题。

为了改进应用程序,它将涉及重写最佳实践中提到的代码。 不要使用闹钟pipe理器来安排后台任务 ,而且如果手机已经睡着,位置将被视为后台任务。 另外你说这是一个后台任务。 使用JobScheduler或Firebase JobDispatcher 。

如果报警pipe理器是更好的select( 这不在这里 ),重要的是要有一个很好的阅读这里调度重复报警 ,但你需要了解的权衡

devise不当的警报可能会导致电池耗尽并给服务器带来很大负担。