Battery Historian 使用及数据分析
adb 对手机的操作
1.重置内部数据,相当于清空
adb shell dumpsys batterystats --reset
2.获取完整的 wakelock 信息
adb shell dumpsys batterystats --enable full-wake-history
3.拔掉 USB 等待一段时间建议长一点,现在随意使用 APP
4.获得电量报告
// > 6.0
adb bugreport bugreport.zip
// <= 6.0
adb bugreport > bugreport.txt
5.提交电量报告,并查看
数据参数详细说明
1.WakeLock 级别
- PARTIAL_WAKE_LOCK: 保证 CPU 保持高性能运行,而屏幕和键盘背光(也可能是触摸按键的背光)关闭。一般情况下都会使用这个WakeLock 。
- ACQUIRE_CAUSES_WAKEUP: 这个WakeLock除了会使 CPU。高性能运行外还会导致屏幕亮起,即使屏幕原先处于关闭的状态下。
- ON_AFTER_RELEASE: 如果释放 WakeLock 的时候屏幕处于亮着的状态,则在释放WakeLock之后让屏幕再保持亮一小会。如果释放 WakeLock 的时候屏幕本身就没亮,则不会有动作。
- API17 被弃用的 WakeLock:保持屏幕长亮
。
SCREEN_DIM_WAKE_LOCK:保证屏幕亮起,但是亮度可能比较低。同时键盘背光也可以不亮。
SCREEN_BRIGHT_WAKE_LOCK :保证屏幕全亮,同时键盘背光也亮。
FULL_WAKE_LOCK:表现和SCREEN_BRIGHT_WAKE_LOCK 类似,但是区别在于这个等级的WakeLock使用的是最高亮度
推荐使用
//在Activity中:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//或者在布局中添加这个属性:
android:keepScreenOn="true"
剩下参数由表格说明

当前 APP Stats
分析当前 APP 电量详细信息
1.从上图可以看出 早上 11:00 - 下午 12: 00 这一个小时内电量下降的最快,耗电量最多的罪魁祸首就是 GPS 和 wakelock
2.在 APP Stats -> Device estimated power 中可以查看在这一小时耗电时常,(由上图 Battery Level 得知电量变化过程是 69 - 61 ,1h 下降 8 )APP 1h 耗电为 5.38 % 还是挺耗电的。
当前 APP 优化建议:
GPS :GPS 可以间断获取,或者使用第三方(高德、百度)它们提供省电模式定位,有 wifi 地方切换 wifi 定位,少用 高精准定位模式。
网络连接: 有 wifi 地方建议切换 wifi
wakelock : 尽量不要使用。
总结-优化方案
1. 加入电量优化白名单。
> /** > * 加入电量白名单 > * > * @param activity > * @param type 1: 启动 设置页面 2:触发系统对话框 > */ > public static void addWhite(Activity activity, int type) { > if (activity == null)return; > WeakReference<Activity> activityWeakReference = new WeakReference<Activity>(activity); > PowerManager packageManager = (PowerManager) activityWeakReference.get().getApplication() > .getSystemService(Context.POWER_SERVICE); > //应用是否在 白名单中 > if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { > if (!packageManager.isIgnoringBatteryOptimizations(activityWeakReference.get().getApplication().getPackageName())) > { > if (type == 1) { > //方法1、启动一个 ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS Intent > Intent intent = new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS); > activityWeakReference.get().getApplication().startActivity(intent); > } else { > //方法2、触发系统对话框 > Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); > intent.setData(Uri.parse("package:" + activityWeakReference.get().getApplication().getPackageName())); > activityWeakReference.get().getApplication().startActivity(intent); > } > } > } > }
2.GPS 优化建议
定位是 App 中常用的功能,但是定位不能千篇一律,不同的场景以及不同类型的 App 对定位更加需要个性化的区分。
选择合适的 Location Provider Android系统支持多个 Location Provider:
GPS_PROVIDER: GPS 定位,利用 GPS 芯片通过卫星获得自己的位置信息。定位精准度高,一般在 10米左右,耗电量大;但是在室内,GPS 定位基本没用。
NETWORK_PROVIDER: 网络定位,利用手机基站和 WIFI节点的地址来大致定位位置,这种定位方式取决于服务器,即取决于将基站或 WIFI 节点信息翻译成位置信息的服务器的能力。
PASSIVE_PROVIDER:被动定位,就是用现成的,当其他应用使用定位更新了定位信息,系统会保存下来,该应用接收到消息后直接读取就可以了。比如如果系统中已经安装了百度地图,高德地图(室内可以实现精确定位),你只要使用它们定位过后,再使用这种方法在你的程序肯定是可以拿到比较精确的定位信息。
使用 Criteria,设置合适的模式、功耗、海拔、速度等需求,系统会返回合适的 Location Provider。 例如你的 App只是需要一个粗略的定位那么就不需要使用 GPS 进行定位,既耗费电量,定位的耗时也久
及时注销定位监听
在获取到定位之后或者程序处于后台时,注销定位监听,此时监听GPS传感器相当于执行no-op(无操作指令),用户不会有感知但是却耗电。
//如果对定位要求不那么严格的话 可以在关闭屏幕的时候可以暂停 public void onPause() { super.onPause(); if(locationManager != null) locationManager.removeListener() }
多模块使用定位尽量复用
多个模块使用定位,尽量复用上一次的结果,而不是都重新走定位的过程,节省电量损耗;例如:在应用启动的时候获取一次定位,保存结果,之后再用到定位的地方都直接去取。
3.网络切换建议 上传下载尽量用 WIFI//优化方案 二 :网络数据切换 if (!BatteryUtils.isPlugged(getApplicationContext())){ //如果没有充电,提醒用户是否有可用 wifi }
4. WakeLock 亮屏,唤醒 CPU 建议
亮屏替换者
//在Activity中:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//或在布局中添加这个属性:
android:keepScreenOn="true"
alarm 闹钟让 CPU 间断式工作
/**
* 开启一个闹钟
* @param context
* @param action
* @param requestId
* @param interval
*/
public static void startTimer(Context context,String action,int requestId,int interval) {
Intent intent = new Intent(action);
PendingIntent sender = PendingIntent.getBroadcast(context, requestId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
int second = calendar.get(Calendar.SECOND);
//延迟一分钟执行
int delay = 60 - second + 1;
calendar.add(Calendar.SECOND, delay);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
String format = new SimpleDateFormat("HH:mm:ss", Locale.CHINA).format(calendar.getTimeInMillis());
Log.d("下次闹钟执行的时间--》","delay: " + delay +", startMillis: " +format);
alarmManager.setWindow(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 100, sender);
} else {
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), interval, sender);
}
}
5. JobScheduler (Service 替代者。 8.0 以后 Google 推荐使用)
a.把工作任务放到合适的时间再去执行,比如充电时间,wifi 连接后
b.也可以把多个任务合并到一起,再选择时间去执行
//需求 现在我需要在充电的状态下并且连接上 wifi 在上传 gps 数据
//jobScheduler 会自动把数据添加到一个队列中
//存入数据
@Override
public int enqueue(JobInfo job, JobWorkItem work) {
try {
return mBinder.enqueue(job, work);
} catch (RemoteException e) {
return JobScheduler.RESULT_FAILURE;
}
}
//在适当的时候取出所有数据
@Override
public List<JobInfo> getAllPendingJobs() {
try {
return mBinder.getAllPendingJobs();
} catch (RemoteException e) {
return null;
}
}
也许有的对这个 jobSchedler 合并任务执行还不是那么清晰,现在看下一个(5 .3 )的录屏
c.在充电并且连接 wifi 的状态下发送数据(这里旋转屏幕是为了发送数据用的)。
- 先说一下演示流程 连接 wifi + 充电 正常发送数据
- 关闭 wifi 发送数据,在打开 wifi 合并发送数据
到这里 咱们电量优化讲的差不多了 最后实际优化了 2% 下去。也还是不错的了