性能优化-耗电优化

耗电优化

耗电检测工具

Battery Historian是一款Google提供的Android系统电量分析工具,能直观显示手机的电量消耗过程。

Battery Historian使用步骤

  1. 初始化Battery Historian,使用adb命令
adb shell dumpsys batterystats --enable full-wake-history

adb shell dumpsys batterystats --reset
  1. 初始化后,操作需要测试耗电的场景
  2. 经过2步骤后,用下面命令将bugreport信息保存为bugreport.txt文件
adb bugreport > bugreport.txt

打开可看到耗电数据,但可读性差,下面转成html

  1. 生成html报告
python historian.py -a bugreport.txt > battery.html

historian.py需要python环境,historian.py脚本可从github下载

historian.py需要和bugreport.txt在同个目录下

  1. 使用Chrome打开生成但HTML文件,即可查看详细报告。

报告参数解析

image.png

三大模块省电优化

移动设备的耗电主要集中在三个模块:显示(屏幕)、CPU、网络模块(蜂窝网络)

1. 显示

对应用程序来说,在使用时屏幕显示的耗电基本没多少优化空间,但可以根据是否长时间没有操作进入熄屏状态。

2. 网络

通常情况下,Wi-Fi连接网络时的功耗低于使用移动网络的功耗。
使用移动网络传输数据,电量的消耗有以下3中状态:

  • Full power:高功率状态,允许最大传输速率操作
  • Low power:低功耗状态,电量消耗大概是Full power的50%
  • Standby:空闲状态,没有数据传输时,电量消耗最少。

在应用中每创建一个新的网络连接,网络模块都会转换到高功率状态,在传完后回到低功耗,转换过程5秒,最后转空闲态。每个数据传输都会导致20秒的电量消耗。

Wi-Fi的耗电与包率(每秒发送和接受的包数)和通道率(网速)这两个因素有关。

优化网络连接降低电量消耗的方案:

  • 尽量在Wi-Fi下使用数据传输(一些不紧急的判断在Wi-Fi环境在传输)
  • 使用Wi-Fi传输数据时,应尽可能增大每个包的大小(不超过MTU),并降低并发包的频率。
  • 在蜂窝网络下,最好做到批量执行网络请求,尽量避免频繁的间隔网络请求。
  • 压缩数据格式,比如使用GZIP压缩传输减少数据量

3. CPU

为了省电和高效管理CPU,Linux内核提供5种变频模式供用户选择使用。但调频需要在Root环境下,应用开发中一般无法使用。在应用中需要注意的是如何减少CPU的开销以达到省电的目的,比如减少计算量。

应用常用优化方案

计算优化

缩短代码产生指令运行的时间,进而减少某个应用程序对CPU时间片的总占用时间。浮点运算比整数运算更消耗CPU时间片,耗电也会增加,所以尽量减少浮点运算
避免浮点运算的方法:

  • 除法变乘法
  • 充分利用移位
  • 查表法,直接使用映射关系,但这个会增加内存开销,视具体场景而定。

避免WakeLock使用不当

在某些场景,比如社交类应用、播放器停留在看歌词页面,需要唤醒手机不要进入息屏睡眠状态。最常用的唤醒手机的方法是使用PowerManager.WakeLock来保持CPU工作并防止屏幕自动变暗关闭。

PowerManager负责对Android设备电源相关进行管理,WakeLock也是一种锁机制,只要应用中有WakeLock,通过相应参数去获取对应的锁,即可达到电源管理目的。

获取WakeLock

private void acquireWakeLock(Context ctx){
    if(null == mWakeLock){
        PowerManager pm = (PowerManager)ctx.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "TestLockService");
        if(null != mWakeLock){
            mWakeLock.acquire();
        }
    }
}

拿到WakeLock后,可以保持完成需要完成的事,但完成后,或者离开这个场景后,需要及时释放WakeLock,否则会带来不可预估的电量消耗。释放锁代码:

private void releaseWakeLock(){
    if(null != mWakeLock){
        mWakeLock.release();
        mWakeLock = null;
    }
}

使用JobScheduler

在Android5.0提供来一个JobScheduler组件,只有在一系列的预置条件满足时,才执行对应的操作,这样既能省电,有保证来功能的完整性。可以在以下场景中考虑使用JobScheduler:

  • 重要不紧急的任务,如定期数据库数据更新和数据上报
  • 耗电较大的任务,比如充电是才执行数据库备份
  • 不紧急可以不执行的网络任务,如可在Wi-Fi下才执行预加载数据
  • 可以批量执行的任务

使用JobScheduler的两个步骤:

  1. 创建JobScheduler

创建JobScheduler,用来初始化一个JobScheduler以及设置触发JobScheduler执行任务的条件。

  • 通过getSystemService()获取一个JobScheduler对象
private JobScheduler mJS = null;
public JobSchedulerManager(Context ctx){
    mContext = ctx;
    mJS = (JobScheduler)mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE);
}
  • 创建一个JobInfo,描述一个任务的执行ID,以及触发这个任务的条件
public boolean addJobSchedulerTask(int task_id){
    JobInfo.Builder builder = new JobInfo.Builder(task_id, new ComponentName("PackgeName", JobSchedulerService.class.getName()));
    
    switch(task_id){
        case 1:
            builder.setPeriodic(1000);
            break;
        case 2:
            builder.setPersisted(false);
            break;
        default:
    }
    if(mJS != null){
        return mJS.schedule(builder.build()) > JobScheduler.RESULT_FAILURE;
    }else{
        return false;
    }
}
image.png
  1. 创建JobSchedulerService继承JobService
public class JobSchedulerService extends JobService{
    @Override
    public boolean onStartJob(JobParameters params){
        //执行具体的任务,最好在异步线程
        return false;
    }
     @Override
    public boolean onStopJob(JobParameters params){
        //取消一个任务
        return false;
    }
}

在AndroidManifest.xml中注册服务



JobSchedulerService必须实现两个方法onStartJob(JobParameters params)和onStopJob(JobParameters params)

  • 任务开始时,执行onStartJob(JobParameters params)方法,触发已经被执行的任务。执行完毕,需要调用jobFinished(JobParameters params, boolean needsReschedule)来通知系统。
  • 系统接受到取消请求,调用onStopJob(JobParameters params)方法取消正在等待执行的任务。

注意:JobService运行在主线程,如果耗时任务,要异步操作来执行。

本文参考书籍《Android应用性能优化最佳实践》

你可能感兴趣的:(性能优化-耗电优化)