前言
起因:在路测阶段有不少同学反映,满电的手机出去路测,回来时已基本没电;也有反馈路测期间手机发烫;
了解原因之前我们先要知道CPU为什么会耗电?
CPU在运行复杂度不同的任务是采用调频处理的,当手机处理复杂任务时,频率也会提高,自然对于电量的需求会增加。另外,当APP进程的CPU使用率超过1%的时候,都是耗电比较大的。
可能导致App耗电过快的原因
1、频繁的交互
正常情况下,关闭后台软件 VS 行程中导航的时候手机耗电一定是差别很大的,行程中涉及司乘同现、路线规划、最佳视野、定位上报...等等
再比如,在玩王者荣耀游戏 VS 听音乐的时候,因为玩游戏的时候会和屏幕产生很多的交互,但是听音乐就不会这样,频繁的交互式非常耗电的。
2、动画效果
顺风车场景包含了大量的动效场景,例如,首页发单控件下拉动效、司乘等待页动效、行程中动效...等等
当我们设计交互动画的效果时,调用的都是view或者其子类,比如按钮在点击前是效果1,点击后变成效果2,设置更复杂的动画,此时view的重绘让CPU或GPU不断计算,耗电量同样会增加。
3、布局文件嵌套太多
app的布局文件影响着app展示给用户的效果,当布局过于复杂,布局文件嵌套太多时,布局xml文件越来越繁多,查找、加载这些文件显示时会造成CPU计算加重,也会影响手机耗电。
4、频繁的网络请求
5、定时任务唤醒CPU
安卓CPU休眠时一种安卓极致省电的一种模式,如果你息屏一段时间,CPU会自动进入休眠。但在某些场景下,比如当订单状态变更时,我们的应用会给你推送通知,当你亮屏打开手机后会看到这条通知,那么它就是唤醒了手机的CPU,而我们知道CPU工作时需要消耗电量,尤其是在频繁唤醒的情况下,或者发送心跳包。
6、频繁切换网络
切换网络往往需要硬件的支持,硬件需要跑起来也是需要电量的,并且数据网络比wifi更加耗电,2G,3G,4G网络耗电都不同。
7、高运算量代码
比如解析json这类耗时时间较长的数据格式,或二进制编码解码等。比如,首页response返回的json体多则几百行,json解析效率主要是解析耗时
8、代码中执行的timer定时器
Android 的 Timer 类可以用来计划需要循环执行的任务,Timer 的问题是它需要用 WakeLock 让 CPU 保持唤醒状态,再加上不恰当的使用WakeLock最终没有合理释放掉,使得系统长时间无法进入休眠,势必导致高耗电
timer实现的源码是用while(true)循环来检测是否到时间点,没到就wait,并且continue
9、传感器
安全需求中的全程开端需要App置于前台(屏幕保持常亮)、端内大部分场景需要GPS请求
10、SD卡读写
11、蓝牙
优化建议
1、减少应用与屏幕的交互
在设计app的时候适当简化用户的操作流程,简化掉可以帮助用户做的,不仅仅是为了省电,也可以提高用户的效率。
2、减少不必要的动画效果
有些复杂的动画效果完全可以省略,采用静态的app启动页,或者是点击事件的交互、页面跳转时就用尽量减少不必要的动画效果。
3、简化布局文件,避免过多的嵌套
4、HTTP请求优化
http请求可以采用gzip压缩减少传输过程中的数据量,app发起http请求和服务端返回的http请求数据都采用gzip压缩
5、json解析
比较流行的有fast jackson,jackson,gson,jackson解析效率相当高,基本是gson的十倍
6、读写优化
尽量减少SD卡读写操作,包括SharedPreferences,能保存在内存中的尽量保存在内存中,不用害怕内存爆掉,内存绝对不会因为多存了几十个变量而溢出的,如果需要保存到SD卡的数据很多,那只能说我们的App在设计实现方面还有问题,建议重新理下App的编码设计或者是功能设计
7、AlarmManager
通过AlarmManager可唤醒设备,但项目中不限制的滥用,也会导致系统被频繁唤醒;
8、尽量使用WiFi
testerhome大神说,因为手机数据流量会调用手机上面的一些硬件设备,从而唤醒cpu增加耗电,这个跟开启摄像头,开启gps是一样的,一涉及调用硬件设备的绝对唤醒cpu,一唤醒cpu耗电绝对增加
9、非必要,则不要监听网络广播
10、非必要,则不要使用后台常驻service
虽然我们很清楚耗电的原因,但涉及的因素方方面面,我们无法改变重构底层代码、无法优化整个系统、技术瓶颈、不得不定时发送心跳包…想做好性能也并非易事。但是我们能够做到是尽量减少交互、改善产品交互逻辑、优化动画效果、简化布局…其实我们能够做的还很多。
耗电举例分析
power_profile.xml 功耗配置文件部分配置如下:
<device name="Android">
<item name="battery.capacity">3450</item>
...
<item name="screen.on">178.708</item>
<item name="screen.full">240.790</item>
...
</device>
这款手机的电池容量为3450mAh,亮屏时电流为178.708mA,亮度调节到最大时电流为240.790mA。这意味着,如果排除其他耗电影响,仅仅亮屏,该手机可以维持3450mAh178.708mA=19.305h(小时);如果将屏幕亮度调到最大,该手机可以维持3450mAh240.790mA=14.327h(小时)。因此,电池容量越大,手机的续航时间一般更长;在手机重度使用的情况下,耗电会加快。
除了屏幕,手机上需要供电的模块还有很多:CPU、相机、闪光灯、音频、视频、蓝牙、modem、wifi、gps。按单位电流值排一个序的话:
相机(平均1152mAh) > modem(最高604mAh) > wifi(发数据370mAh) > CPU(最高频率290mAh) > 屏幕(最亮240mAh) > 音频(75mAh) > 视频(50mAh) > GPS(49mAh) > 蓝牙(8mAh)
将电池容量分成100隔的话,每隔电就是34.5mAh,既如果一个小时内用了34.5mA的电量,那就会掉一个隔电。参考这些电流值,可以很容易知道:手机拍照是很耗电的,使用数据流量看视频也是很耗电的,重度使用情况下,手机也就能使用2~3个小时。但如果手机一直处于休眠状态,CPU的单位电流值不到2mAh,这样待机个把月也是可以的。所以,一个正常的手机,电池是否耐用,是跟个人的使用习惯相关的。
我们平时分析的功耗问题,是在同等条件下的对比试验,找到异常耗电的原因。譬如:手机的初始条件相似(电池容量、相同的应用等),在同样的环境下放置一个晚上,如果对比机出现明显的掉电异常,就可以通过电量日志找到异常耗电的原因。
参考文献
官方建议优化的一些方法
https://developer.android.google.cn/training/monitoring-device-state/index.html
对低电耗模式和应用待机模式进行针对性优化
https://developer.android.google.cn/training/monitoring-device-state/doze-standby.html
Android 7.0新特性对电池管理进一步加强,一些新的变化可能多对我们现有的业务会造成影响需关注
https://developer.android.google.cn/about/versions/nougat/android-7.0-changes.html#perf