1.简介
应用电量损耗主要在获取网络数据、休眠唤醒CPU、CPU高负荷执行代码、LCD亮度,这里总结了电量损耗的原因以及相关解决策略,其中大部分内容参照谷歌给出的教程。
2 网络访问策略
在没有连接到网络的情况下访问网络不仅无法得到想要的结果,反而会导致不必要的电量损耗。另外通过移动网络(2G/3G/4G)相对WIFI来讲更加耗电,制定合理的网络访问策略能很大的节省电量。
2.1 无网络下访问策略
在无网络的情况下,访问网络进行数据读取操作是没有必要。测试中发现很多应用都会尝试去获取数据,更有些极端的情况是应用线程中一种循环尝试,导致CPU占用率一直很高。
因此可以首先通过ConnectivityManager先进行网络判断,如果网络无连接则不进行下载处理;接下来接收action为android.net.conn.CONNECTIVITY_CHANGE广播再判断网络是否连接再次启动任务进行下载。
网络判断如下:
广播侦听AndroidManifest中自定义的BroadcastReceiver加入:
2.2 移动网络与WIFI下的网络请求策略
移动网络通常需要算流量计费,这意味着需要支付更多的费用,不单如此使用移动网络的功耗要远远大于WIFI。因此在移动网络情况下,多方面考虑都有必要减少网络操作。
当然用户可能会长时间只使用移动网络,对于这种情况下可以适当降低网络请求频率,特别是对于定时更新检测操作。当用户切换到数据网络时,有必要主动挂起下载并等待连接WIFI后再进行恢复下载。
判断是否为WIFI网络如下:
2.3 电量与数据更新策略
当电池低电时,可以将更新频率设为最低或者不做更新检测;当正在充电时,可以将更新频率设为最高。
通过BatteryManager发送粘性广播Intent.ACTION_BATTERY_CHANGED可以直接获取电池充电状态。获取充电状态如下:
当充电状态变化时BatteryManager会发送action为android.intent.action.ACTION_POWER_CONNECTED和android.intent.action.ACTION_POWER_DISCONNECTED广播。因此注册广播侦听:
广播中获取充电状态:
2.4 移动网络下网络请求策略
通常设备在不工作状态下都会进入低功耗状态,如果被激活,那么恢复到低功耗状态需要等待一段时间,例如典型的 3G 无线电网络有三种能量状态:
- Full power:当无线连接被激活的时候,允许设备以最大的传输速率进行操作。
- Low power:一种中间状态,对电量的消耗差不多是 Full power 状态下的50%。
- Standby:最小的能量状态,没有被激活或者需求的网络连接。
在低功耗和空闲的状态下,电量消耗会显著减少。这里也会介绍重要的网络请求延迟。从 low power 能量状态返回到 full power 大概需要花费1.5秒,从空闲能量状态返回到 full power 状态需要花费2秒。
为了最小化延迟,状态机使用了一种后滞过渡到更低能量状态的机制。下图是一个典型的 3G 无线电波状态机的图示(AT&T电信的一种制式)。
由于存在状态切换延迟,因此最好将数据请求放在一段时间内处理,而不是频繁唤醒导致碎片化问题。具体查看谷歌教程:https://yazone.gitbooks.io/android-training-course-in-chinese/content/connectivity/efficient-downloads/efficient-network-access.html
3. 数据缓存策略
能用缓存尽量用缓存,使用缓存的目的不仅仅是因为数据读取速度以及流量问题,缓存还可以减少因为网络访问带来的电量损耗。
4. Alarm定时任务
Android提供了AlarmManager用来执行定时回调,用户可以设置ELAPSED_REALTIME、RTC、ELAPSED_REALTIME_WAKEUP以及RTC_WAKEUP,其中带_WAKEUP后缀类型将使设备从休眠状态中唤醒。我们知道当CPU处于休眠状态时功耗相当的低,基本不会怎么耗电,而被唤醒后功耗将大大增加。
当应用频繁唤醒CPU时,会因为CPU长期处于高功耗的状态下,导致系统待机时间显著减少,虽然应用可能只是做了个状态检测。
因此对于不需要及时通知用户的行为,例如应用检测更新,应用应该尽量使用不带后缀_WAKEUP的类型来执行定时任务。而对于多个需要唤醒CPU的操作,应该尽量在同一时刻触发。
在Android 5.0后,系统提供了JobScheduler给应用来批量处理非紧急的定时任务。基于相同原理,小米提出了系统时钟对齐的概念,通过修改系统来减少CPU被唤醒的次数,不过这样有可能会导致应用响应有一定的延时,这个需要权衡。
(JobSheduler用法参见博客http://blog.csdn.net/cuiran/article/details/42805057)
5. 界面刷新与算法优化
当界面刷新时,电流会产生跳变,例如动画、滑屏,功耗也将显著增加,因此没有任何交互时最好不要做动态效果,例如跑马灯。
界面刷新率越高,算法越复杂,CPU运算量就越大,从而导致的功耗就越大。运算量越小的话流畅度相对来讲也会越高,关于“卡”的问题后面再进行讨论。
6. 应用界面亮度
除了系统屏幕亮度外,应用界面表现出越亮,功耗也会越大,例如黑色背景比白色背景要省电得多。在阅读应用中,对黑底白字和白底黑字的阅读界面两者来讲,前者比后者省电。对于这种需要长时间使用的应用来讲,设计时是有必要考虑暗色背景。
调节屏幕亮度100%的情况下,测试下面两个背景图中前一个功耗要比后一个功耗大80mA以上。
7. BroadcastReceiver使用策略
当应用接收到一个广播时,可能会唤醒进程进行操作,在无网络状态下进行需要网络的操作会带来不必要的功耗问题。
考虑以下场景:当应用收到一个广播后,启动一个线程去下载图片。这里在下载图片前可以先判断网络是否连接,可以省却了请求操作;更进一步在启动线程前加入判断,可以省却线程创建带来的资源消耗。没网络的时候,这个广播可以不必侦听,通过PackageManager的setComponentEnabledSetting可以开启关闭应用组件。如下开启广播组件:
我们只需要侦听网络连接状态一个广播,网络连接打开后开启广播接收者组件,关闭网络时关闭广播接收者组件。
同样对于其他广播,动态更改接收广播策略(动态注册或设置组件是否可用)有助于降低应用的功耗,例如应用可见时才接收广播,如电量变换、下载进度侦听广播等。
8. 电量分析工具
Google推出的Battery Historian能够分析adb bugreport导出信息并视图化显示。如下图:
Battery Historian相关内容将在接下来介绍。
9. 总结
电池电量消耗归根到底是硬件在工作,硬件是否需要工作以及工作时间长短由软件控制,例如优化算法可以减少CPU运行时长、修改网络访问策略降低网络模组工作时长等。优化的根本就在于让软件少做事,做真正需要做的事。