前言:
功耗一直是Android的老大难问题。Android 6.0 对于对于功耗的优化比较明显。本文对功耗优化的feature的Google Training文档进行理解性的翻译,有不尽如人意的地方,请斧正。
原文地址:
http://developer.android.com/training/monitoring-device-state/doze-standby.html
正文:
Doze 和 App Standby 优化
从Android(API 23)开始,Android采用两种省电机制来延长电池使用时间,对于用户来说就是当没有连接电源的时候来如何合理管理app的行为。
这两种机制分别是:
Doze : Doze 是当设备长时间没有用时 通过延迟后台CPU 和 控制App的网络活动 来达到降低电池功耗。
App Standby : App Standby 是当最近没有和用户交互的App,此机制会延迟它的后台网络活动。
Doze 和 App Standby 管理所有在Android6.0或更高版本上运行的APP的行为,而不管这些APP是否专门针对API 23专门开发的。为了确保最好的用户体验,请在Doze和 App Standb模式下测试你的APP,并在你的代码中做必要的调整。下面将谈谈关于此的详细信息。
了解DOZE模式
如果用户让手机不充电并静置一段时间,保存屏灭,那么设备就会进入Doze模式。在DOZE模式下,手机系统将通过限制APP访问网络 和 密集CPU服务来尝试节省电量。同时它也阻止APP正在访问的网络,并延迟这些APP的工作,同步和标准alarm。
每隔一段时间,系统会退出DOZE模式一段较短时间让APP去完成那些被延迟的活动。这段较短时间称之为 maintenance window:
Maintenance Window : 在Maintenance Window这段时间内,系统会执行所有被延迟的 同步,工作,alarm,并且可以访问网络。
图 1. DOZE提供一个周期性的Maintenance Window让所有APP去用网络和执行所有延迟的活动。
在每个maintenance window结束后,系统又会进入DOZE模式,暂停所有的网络请求 和 延迟所有的工作, 同步操作, alarm。随着时间的推移maintenance window起来的频率越来越少,这样有助于当设备不连接充电器并长期不使用的情况下降低电池功耗。
只要用户唤醒手机并一直使用它, 或保持屏幕亮着,或一直在充电,那么系统不会进入DOZE模式,所有APP正常执行他们的活动。
Doze模式下的限制
当处于DOZE模式下,如下所述的限制条件将用于APP:
1. 网络请求被暂停。
2. 系统会忽略 wake locks。
3. 标准 AlarmManager
alarms(包括setExact()
和setWindow()
)被延迟到下一个maintenance window执行。
3.1. 如果你非要在DOZE模式下设置并启动alarm,就用setAndAllowWhileIdle()
或setExactAndAllowWhileIdle()
。--译者注:这两个函数在API23新加的,参考https://github.com/android/
3.2. 用 setAlarmClock()
设置的alarm,会正常的启动 --也就是说系统退出DOZE模式再才执行这些alarm。
4. 系统不会执行WI-FI的扫描。
5. 系统不允许同步适配器 sync adapters 执行。
6. 系统不允许 JobScheduler
执行。
调整你的APP以适应DOZE模式
DOZE能对APP造成不同的影响,这取决于他们的能力和他们使用的services。 在DOZE的循环机制中,不经过修改,很多APP的功能还是能够正常运行的。但是在某些情况下,你必须优化你的APP管理 网络, alarms,jobs ,sync同步操作 的方式。APP理应能够在每个maintenance window期间有效的管理活动。
DOZE模式特别容易影响AlarmManager
的alarm和定时器的活动,因为在处于DOZE模式下,Android 5.1 (API 22)或更低版本的alarm是不会触发的。---译者注:特别注意这个,APP应该这个针对修改一下。
对于有助于alarm的调度, Android 6.0 (API 23)介绍了两个新的AlarmManager
方法setAndAllowWhileIdle()
和setExactAndAllowWhileIdle()
。这些方法,你可以设置alarm并启动触发它,即使设备处于DOZE模式。
注意:setAndAllowWhileIdle()
或setExactAndAllowWhileIdle()
,每个APP每15分钟最多只能启动触发一次。
DOZE模式对网络请求的限制也可能会影响到你的APP,特别是这个APP依赖于实时时钟消息或者是通知notification。如果你的APP需要一个持久的网络连接来接收消息,那么你可以使用Google Cloud Messaging(GCM),如果可以的话。
为了确认你的APP在DOZE模式下有预期的行为,你可以用adb 命令来强制系统进入或退出DOZE模式来观察你的APP的行为。更详细的信息,请参考Testing with Doze and App Standby 。
了解App Standby
App Standby 允许系统来决定一个当用户并非活跃的使用的APP是否进行闲置(idle)。系统来做这个决定,是当用户在一段确定的时间内没有触发这个APP,但是以下任一条件则不能触发App Standby:
1. 用户明确的启动了这个APP。
2.这个APP现在有一个前台进程(若是一个Activity或前台service亦是如此,又或者被另一个Activity或前台service调用)。
3. 这个APP产生一个通知能在锁屏或通知栏上被用户看到。当用户给设备插入充电,系统会从standby状态释放出来,并允许他们自由的访问网络和执行任何暂停的jobs 和 syncs 。如果设备闲置很久,系统允许闲置APP一天访问一次网络。
当设备空闲的时候用GCM来与你的APP进行交互
Google Cloud Messaging (GCM) 是一个云到端的服务,让你在Android设备上支持后端服务和应用程序之间的实时下游消息。GCM提供一个单一的持续的到云端的连接;如果需要实时消息,所有APP有共享这个连接。这对比众多APP都去维护各自独立的永久连接(没必要,这种方式耗电迅速),共享连接能显著的优化电池功耗。正是这个原因,如果你的APP需要与后端服务消息集成,我们强烈建议你用GCM,如果可以的话,这样远比你维护一个自己的持久连接要好。
GCM是通过高优先级GCM消息的方式工作在DOZE和 AppStandby模式下。GCM高优先级消息让你可靠的唤醒你的APP去访问网络,即使是设备在DOZE模式下还是APP在App Standby模式下。在DOZE或App Standby模式下,系统发送消息让该APP一个临时的网络访问服务和局部的wakelocks,然后返回到设备或APP空闲状态。
高优先级GCM消息不会对DOZE模式起反作用,同时它也不会影响任何APP的状态,它是意味着你的APP能用它来进行高效的交流,从而最大限度的降低系统和设备对电池的影响。
作为一般的最佳实践来说,如果你的APP需要下游消息,则应该使用GCM。如果你的服务器和客户端已经使用GCM,请确保你的服务对于重要的消息使用了高优先级消息机制,因为这样才能可靠的唤醒你的APP,即使设备在DOZE状态。
对其他情况的支持
几乎所有的APP理应能够通过很好的管理 网络连接,alarms, jobs, syncs, 并运用GCM的高优先级消息机制 来支持DOZE模式。对于一类狭隘的用例,这可能是不足够的。基于此,系统提供了一个可配置的APP白名单来避免部分APP受到DOZE和App Standby优化的影响。
被加入白名单的APP可以使用网络,并在DOZE和App Standby模式下能持有部分唤醒锁(partial wake locks)。但是其他的限制同样适用于白名单APP,就像他们做其他APP一样。例如:白名单APP的 jobs, syncs仍倍延迟,并且通过
APP可以检查它是否在当前的白名单中,调用函数AlarmManager
管理的定期alarm不会被触发。isIgnoringBatteryOptimizations()
即可。
同时用户可以手动的配置这个白名单,路径 Settings > Battery > Battery Optimization 。另外,系统也提供方法让APP去问用户是否把本APP加入到白名单中。
1. APP可以触发 ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS
意图让用户直接添加到白名单中。
2. APP可以持有 REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
权限,这能触发一个系统dialog去让用户直接把此APP加入到白名单,而不用用户去settings里面设置。APP也可以通过 ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
意图去触发这个dialog 。
3. 用户可以根据需求手动的移除白名单。
在询问用户去把你的APP加入到白名单之前,请确认APP匹配白名单的合适的用例,即是否真的有必要加入白名单。
注意:谷歌市场政策是在Android6.0及其以上禁止APP直接忽略电源管理功能(即DOZE和 App Standby), 除非你的核心功能受到不利的影响。
Testing with Doze and App Standby
为了尽大的提升用户体验,你应该测试你的APP 在DOZE 和 App Standby模式下的情况。Testing your app with Doze
你可以按如下步骤测试你的APP在DOZE模式下的情况:1. 配置一个具有Android 6.0(API 23)或更高版本 system image的 设备或 虚拟设备。
2. 连接设备到你的开发机上并安装你的APP。
3. 运行你的APP,并保持它激活。
4. 用如下命令强制系统进入 循环的DOZE模式:
$ adb shell dumpsys battery unplug
$ adb shell dumpsys deviceidle step
$ adb shell dumpsys deviceidle -h
5. 当重新激活你的设备观察你的APP的行为,确保设备退出DOZE模式后你的APP能恢复正常。
Testing your app with App Standby
测试你的APP的App Standby模式:1. 配置一个具有Android 6.0(API 23)或更高版本 system image的 设备或 虚拟设备。
2. 连接设备到你的开发机上并安装你的APP。
3. 运行你的APP,并保持它激活。
4. 用如下命令让APP强制进入App Standby模式:$ adb shell dumpsys battery unplug
$ adb shell am set-inactive <packageName> true
5. 用如下命令模拟唤醒APP:
$ adb shell am set-inactive <packageName> false
$ adb shell am get-inactive <packageName>
6. 当你的APP唤醒后观察它的行为。确保APP 能从App Standby模式后正常恢复。特别是,你应该确认APP 的通知(notification)和 后台工作 能像预期那样正常继续工作。
白名单例子
如下表强调的这些可接受的使用案例。通常APP不应该在白名单中,除非DOZE和App Standby模式影响了你的核心功能,并且这里有一个技术原因,为什么你的APP不能用GCM高优先级消息机制。
更多消息请参考 Support for Other Use Cases。
类型 | 用例 | 能用GCM吗? | 白名单是否合适? | 注意 |
---|---|---|---|---|
即时通讯,聊天,电话程序 | 设备处于DOZE和App Standby模式下,需要传送实时消息到用户 | 能,能用GCM | 不合适 | 应该使用GCM高优先级消息机制来唤醒APP和网络访问。 |
能,但是不能用GCM的高优先级消息机制。 | ||||
即时通讯,聊天,电话程序,企业VOIP程序 | 不能,不能使用GCM,因为技术原因依赖于其他消息服务。 | 合适 |