1.官方的建议
1.1 电池续航时间优化(Optimizing Battery Life)
参考文章:优化电池使用时间
已有中文的详细说明,此处做简要说明:
(1)监控电池电量和充电状态(Monitoring the Battery Level and Charging State)
通过系统广播,获取充电状态和电池电量的变化来调整数据更新等操作;如在充电时,更新数据及应用,在低电量时,减少更新频率或停止gen
(2)确定和监控基座对接状态和类型(Determining and Monitoring the Docking State and Type)
和监控充电状态类似,通过系统广播,获取充电基座类型(车载基座、桌面基座),改变应用更新频率和方式
(3)确定和监控网络连接状态(Determining and Monitoring the Connectivity Status)
也和监控充电状态类似,根据当前连接网络的类型采取不同的策略。一般情况WiFi耗电要比移动数据流量低很多。监听CONNECTIVITY_CHANGE,可以在网络状态变化时调整策略
(4)根据需要操作广播接收器(Manipulating Broadcast Receivers On Demand)
主要说明可通过PackageManager的setComponentEnabledSetting方法来改变组件的启用与禁用。需要注意的是,此方法会导致应用的通知栏变化,不过系统会发送Intent.ACTION_PACKAGE_CHANGED广播,而且要留心这种变化的持续性,避免误认为广播接收器偶尔不正常。
1.2 数据传输中减少耗电
参考文章: Transferring Data Without Draining the Battery
此系列文章主要介绍与数据传输相关方面,减少电量消耗。首先,以3G数据网络状态机为例,说明无线射频在standby 、low power 、full power三种状态下的切换,一般减少频繁的网络连接,而延长在full power模式,获取更多数据,如采取预获取、合并获取数据等;另一方面,减少不必要的重连接和获取无用的数据;最后还是要区分在不同的网络类型下,采用不同的策略,考虑GPRS等网络实际的速度带宽等
1.3 针对 Doze和App Standby的优化
文章链接:Optimizing for Doze and App Standby
在Android6.0上引入了Doze和应用的Standby。在Doze模式下,应用的网络连接,CPU的使用都被严格控制,甚至唤醒锁(wake lock)和普通的Alarm也被忽略,但是会周期性地退出,使应用可以完成被推迟的工作
为了适配此种模式,一方面考虑其被延迟执行的影响(如心跳等),以及在后台,程序是否有必要执行某些操作,另一方面,它还是保留了setAlarmClock() 和提供setAndAllowWhileIdle() 和 setExactAndAllowWhileIdle(),但应考虑不同设备,应用实际唤醒间隔时间。在官方描述是不少于9分钟或者15分钟。
应用的Standby,主要是指系统判定用户不在使用应用时,推迟应用在后台的活动,包括网络访问、周期任务等;而判定的条件,排除此应用具有前台进程和具有通知栏。
然后都给出了测试方法,可以直接利用adb命令进入测试模式
(1)Doze
$ adb shell dumpsys battery unplug
$ adb shell dumpsys deviceidle step
第二条指令需要执行多次
(2)Standby
$ adb shell dumpsys battery unplug
$ adb shell am set-inactive <packageName> true
退出此模式:
$ adb shell am set-inactive <packageName> false
$ adb shell am get-inactive <packageName>
最后说明的是进入Doze是有比较严格的条件的,官方说明是在屏幕关闭后,没有连接电源且没有活动一定时间后(如1小时),而且屏幕一旦开启或连接电源即退出Doze模式。同时系统也提供了白名单功能,如果觉得自己的应用进入Doze模式后,依然需要正常使用,可以通过ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS 引导用户将自己加白。然而厂商实际执行可能会有差别,如在华为手机上,屏幕关闭几分钟后,应用就已经被挂起;定制ROM比较严重的厂商,还会对屏幕关闭后,执行杀死进程,关闭网络等操作,都需要额外的考虑。细节不描述,因为这是保活的问题,具体可参考Android微信智能心跳方案和其它方案,但需要考虑对自身应用耗电的影响,比如心跳包无法发出,导致频繁重连接,导致频繁的证书交换(在此提及的原因是用https或者直接利用ssl,连接过程中验证服务端都会涉及到证书链的下载,而单个证书可能就有几K大小,证书链可能会到10K,特别是在数据网络下,频繁的连接带来的消耗非常大)等都是耗电耗流量大户。
2.其他经验
此处的经验是在电量统计的基础上得出的(后面会做些电量统计的说明)。耗电大户主要是设备唤醒、CPU和网络、传感器。
(1)设备唤醒单提出来说是因为通过Alarm可唤醒设备,而项目中不限制的滥用,导致系统被频繁唤醒;再加上不恰当的使用wake lock,没有释放wake lock,使得系统长时间无法进入休眠,势必导致高耗电,可参考(android设备休眠)
( 2)CPU和网络耗电方面,主要是减少I/O操作(包括数据库操作),大量的计算;减少网络网络请求次数和数据量
(3)传感器:设备屏幕亮度、颜色背景等需要考虑,但除了阅读类等应用,一般是不太考虑屏幕消耗的。更多的是对GPS的使用注意,减少无用的GPS请求和及时关闭GPS搜索,比如室内是无法使用GPS完成定位的。
原来统计耗电都参考《深入浅出Android App耗电量统计》
工具如腾讯的GT值得推荐
3.统计、查找、分析并优化实践
此处的统计主要针对batterystats上进行。在Android5.0已经提供了adb shell dumpsys batterystats命令,而且在Android6.0上数据统计更详细。官方的文档Batterystats and Battery Historian Walkthrough,简单的测试步骤:
(1)插入手机
$adb shell dumpsys batterystats --reset
(2)拔掉手机,开始测试
(3)$adb shell dumpsys batterystats > filename.txt 保存统计数据
然后可以下载并使用官方的python脚本生成html查看,也可以直接用文本文档查看。统计数据中包括了详尽的电量,wake lock,网络使用的统计,具体到UID及其中的进程。列出一部分微信的在自己手机中使用的数据,有删减:
u0a90:
Mobile network: 908.38KB received, 144.94KB sent (packets 1063 received, 1219 sent)
Mobile radio active: 5m 27s 337ms (31.9%) 15x @ 143 mspp
Wi-Fi network: 3.52MB received, 454.37KB sent (packets 3628 received, 3645 sent)
Wake lock WakerLock:180110109: 12s 444ms partial (52 times) realtime
Wake lock *alarm*: 3s 362ms partial (24 times) realtime
...
TOTAL wake: 59s 188ms partial realtime
Foreground activities: 18m 37s 145ms realtime (32 times)
Foreground for: 1h 49m 14s 993ms
Total cpu time: u=3m 57s 240ms s=1m 4s 170ms p=0mAh
Proc com.tencent.mm:tools:
CPU: 1m 57s 260ms usr + 31s 570ms krn ; 0ms fg
3 starts
Proc com.tencent.mm:exdevice:
CPU: 1s 290ms usr + 2s 590ms krn ; 0ms fg
Proc com.tencent.mm:
CPU: 1m 46s 610ms usr + 22s 920ms krn ; 4m 21s 940ms fg
Proc com.tencent.mm:push:
CPU: 7s 250ms usr + 5s 50ms krn ; 0ms fg
Proc com.tencent.mm:sandbox:
CPU: 0ms usr + 0ms krn ; 0ms fg
1 starts
Apk com.tencent.mm:
Wakeup alarm *walarm*:ALARM_ACTION(7277): 22 times
Wakeup alarm *walarm*:com.tencent.mm/.booter.MMReceivers$AlarmReceiver: 7 times
Service com.tencent.mm.sandbox.updater.UpdaterService:
Created for: 11s 53ms uptime
Starts: 1, launches: 1
...
Service com.tencent.mm.plugin.webview.stub.WebViewStubService:
Created for: 0ms uptime
Starts: 0, launches: 9
从上能够分析出微信在这段测试时间详细的网络消耗,包括移动网络和WiFi网络,CPU的使用,Alarm,以及Service的启动和运行时长等信息,基于此,再逐项排查和减少电量消耗。对于alarm的触发,网络的请求问题的定位从代码上能比较方便的搜索到,但是CPU的消耗,则需要通过Android提供的Profiling工具来实现,它会帮你定位出CPU的时间都消耗在哪个函数上。具体可参考Profiling with Traceview and dmtracedump,网络上有很多的使用教程。
简单附上统计的说明:
应用UID:u0a90
移动网络数据统计和时长统计
WiFi网络数据统计
Wake lock统计,包括通过alarm触发次数
应用前台页面信息
CPU使用统计,包括各个进程的使用信息
Servce信息