×

Android App优化之电池省着用

96
anly_jun
2016.10.08 22:41* 字数 1913
cover

引言

  1. 背景:Android App优化, 要怎么做?
  2. Android App优化之性能分析工具
  3. Android App优化之提升你的App启动速度之理论基础
  4. Android App优化之提升你的App启动速度之实例挑战
  5. Android App优化之Layout怎么摆
  6. Android App优化之ANR详解
  7. Android App优化之消除卡顿
  8. Android App优化之内存优化
  9. Android App优化之持久电量
  10. Android App优化之如何高效网络请求

电量使用优化, 基本上是我们最不怎么关注的一项优化. 可能很多公司连QA/Tester也不会关注测试App电量的使用. 一般来说开发和测试的测试设备也一直是连着USB处于充电状态的, 感官上也体会不到电量的损耗.

然而, 对于用户来说, 实际上App的电量损耗也是用户体验的一个方面. 特别是当今人们对移动设备的依赖度越来越高, 电量也是用户特别关注的.

今天我们就来聊聊Android App的电量优化.

1, 分析电量的使用情况

老套路, 上来还是先介绍下我们使用什么工具来做电量分析.

1.1 Batterystats & bugreport

Android 5.0及以上的设备, 允许我们通过adb命令dump出电量使用统计信息.

1, 因为电量统计数据是持续的, 会非常大, 统计我们的待测试App之前先reset下, 连上设备, 命令行执行:

$ adb shell dumpsys batterystats --reset
Battery stats reset.

2, 断开测试设备, 操作我们的待测试App.
3, 重新连接设备, 使用adb命令导出相关统计数据:

// 此命令持续记录输出, 想要停止记录时按Ctrl+C退出.
$ adb bugreport > bugreport.txt

导出的统计数据存储到bugreport.txt, 此时我们可以借助如下工具来图形化展示电池的消耗情况.

注意, 官方SDK文档导出文件方式为:
adb shell dumpsys batterystats > batterystats.txt
使用python historian.py batterystats.txt > batterystats.html查看数据
是battery-historian老版本的使用方式. 目前Battery Historian已更新2.0版本, 推荐使用bugreport方式导出数据分析, 可以看到更多信息.

1.2 Battery Historian

Google提供了一个开源的电池历史数据分析工具 -- Battery Historian.

1.2.1 安装

按照Battery Historian在github上的readme, 一步步安装即可.

需要注意的是, Battery Historian是Go语言的, 安装Go的时候需要配置其bin的环境变量.
Python环境需要是2.7的(3.x不行), 建议使用pyenv管理本地的python环境.
另外, 因为Battery Historian是一个网页版工具, 涉及一些JS引用, 有时需要翻墙.

安装完成后, 执行:

cd $GOPATH/src/github.com/google/battery-historian
go run cmd/battery-historian/battery-historian.go [--port <default:9999>]

程序运行在http://localhost:9999, 如下:

battery historian running web

1.2.2 界面

导入我们在第一步通过adb bugreport生成的bugreport.txt文件:

battery historian

2, 主要的耗电因素

battery usage

从手机的电池详情统计可以简单看出, 手机中最耗电的模块肯定是屏幕了, 接着就是网络相关, 另外可能的耗电大户还有GPS芯片, Camera等.

对于一个App, 对应因素主要有:

2.1 网络请求

我们可能会有发现:

  • 测试用的手机充满电放了一个十一假期还有电, 是因为测试手机没有上SIM卡.
  • 飞行模式下的手机灭屏下, 可能可以放一个月都还有电.

这是因为:

  • 手机的通过内置的射频模块和基站几乎, 从而链接上网的, 而这个射频模块(radio)是非常耗电的.
  • 为了控制这个射频模块的耗电, 硬件驱动及Android RIL层做了很多处理. 例如可以单独关闭radio(飞行模式), 间歇性假休眠radio(有数据发生时才上电, 保持一个频率的与基站交互)等等.

现如今App都是移动互联网App, 不可避免的会有大量的网络请求, 会导致radio一直处于活跃状态, 从而耗电量增加.

2.2 WakeLock

Android系统本身为了优化电量的使用, 会在没有操作时进入休眠状态, 来节省电量. 当然, 为了便于开发(很多应用不可避免的希望在灭屏后还能运行一些事儿, 或是要保持屏幕一直亮着--比如播放视频), Android提供了一个PowerManager.WakeLock的东西.

我们可以用WakeLock来保持CPU运行, 或是防止屏幕变暗/关闭, 让手机可以在用户不操作时依然可以做一些事儿. 然而, 获取WakeLock很容易, 释放不好就会成为难题, 消耗电量.

例如我们获取了一个WakeLock来保持CPU运转, 做一个复杂运算并将数据上传到后台服务器, 然后释放该WakeLock. 然而这个过程可能并不像我们想象的那么快, 可能因为比如服务器挂掉, 计算出了异常等等WakeLock没有释放. 问题就来了, CPU会一直得不到休眠, 而大大增加耗电.

另外, WakeLock还有android:keepScreenOn属性, 还可以让屏幕常量, 这可是耗电大户.

2.3 GPS

应用中经常会用到定位服务, Android提供了Network定位和GPS定位. 相对来说, GPS会精确得多, 对于一些诸如跑步, 导航类的应用基本会使用GPS定位. 然而, GPS定位也会消耗大量的电量.

3, 尽可能减少App的电量消耗的建议

了解了上述的主要的耗电因素, 还有一些程序的耗电问题, 我们通过Battery Historian也可以分析.

针对这些耗电情况, 给出如下优化建议:

3.1 优化网络请求

这个会在网络优化那篇中细聊, 在此略过.

3.2 谨慎使用WakeLock

  1. WakeLock获取释放成对出现.
  2. 使用超时WakeLock, 以防出异常导致没有释放.
// Acquires the wake lock with a timeout.
acquire(long timeout)

3.3 监听手机充电状态

BatteryManager会发送一个包含充电状态的持续广播, 我们可以通过此广播获取充电状态和电量详情:

IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = context.registerReceiver(null, ifilter);

注意: 因为这是一个持续广播, 我们无需写receiver, 可以直接通过intent获取相关数据.

例如, 如果设备正在充电:

// Are we charging / charged?
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                     status == BatteryManager.BATTERY_STATUS_FULL;

// How are we charging?
int chargePlug = battery.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB;
boolean acCharge = chargePlug == BATTERY_PLUGGED_AC;

另外我们也可以监听充电状态的变化, 只要设备连接或断开电源, BatteryManager就会广播相应的操作, 我们可以注册receiver来监听:

<receiver android:name=".PowerConnectionReceiver">
  <intent-filter>
    <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
    <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
  </intent-filter>
</receiver>

监听电池状态, 可以让我们将一些操作放在充电或是电量足够的情况下进行, 以提升用户体验. 例如用户数据同步, Log上传等.

3.4 Doze and App Standby

Android 6.0提供了两个用来节省电量的技术Doze和App Standby.

  • Doze
    瞌睡. 如果设备闲置了一段较长时间, Doze技术将通过延迟后台网络活动, CPU运行等来减少电量损耗.

  • App Standy
    应用待机. 不是最近得到过用户"宠幸"的App, App Standy将延缓这个应用的后台网络活动.

因为所有Android 6.0及以上的设备上, Doze and App Standby都会运行. 可能会影响你的App的运行, 具体的适配请参考官方文档.

3.5 关于定位

  • 定位中使用GPS, 请记得及时关闭
// Remove the listener you previously added
locationManager.removeUpdates(locationListener);
  • 减少更新频率
  • 根据实际情况选择GPS或网络或两者. 只使用一个会降低电量损耗.

转载请注明出处, 欢迎大家分享到朋友圈, 微博~

Android经验谈
Web note ad 1