Android耗电优化需要注意的要点

685 阅读5分钟

在应用开发中,耗电是我们需要关注的重点。但是,开始进行耗电优化时,我们常常感到无从下手。这篇文章将介绍耗电优化的相关要点,让我们优化时有一个方向。

传感器

大多数Android设备都内置传感器,如果你的 App 需要使用传感器,记得在不使用时及时取消注册监听,否则会让 app 在后台一直接收数据,造成不必要的耗电。

image.png

如上图,谷歌官方文档上写的很清楚。当我们在Activity切到后台后依然会调用传感器,一般来说onPause之后就已经是非业务场景,在 destroy之前都会持续占用传感器,造成不必要的耗电。

其次,注册传感器时,可以选择传感器精度,精度越高耗电也就越多,我们需要根据业务实际需求选择合适的精度,不要盲目追求高精度。

定位

定位从获取方式可以分为两种,主动获取 或 被动定位。主动获取又可以分为 GPS 和 网络定位。

  • GPS_PROVIDER(GPS方式):

    1. GPS定位,精准度高耗电量大;
    2. 室内GPS定位基本没用。
    3. 绝大部分用户默认不开启GPS模块;
    4. 从GPS模块启动到获取第一次定位数据,可能需要比较长的时间;
  • NETWORK_PROVIDER(网络定位):

    网络定位,利用基站和WIFI节点的地址来定位,取决于将基站或WIF节点信息翻译成位置信息的服务器能力;定位快耗电低。

  • PASSIVE_PROVIDER(被动定位):

    被动定位,使用系统中其他应用的定位信息。

如果我们开发的 app 使用了定位服务,需要注意:

  1. 根据使用场景选择定位模式,优先考虑使用网络定位(比如定位城市)
  2. 前台定位时,界面 onPause 则停止位置更新;后台定位时,根据页务需求控制位置更新时间间隔。
  3. 如果应用是多模块开发,模块之间应该尽量复用位置信息,不要同时定位

WakeLock

Android 运行在很多移动设备上,考虑到功耗原因,引入了 autoSleep的休眠方式,当检测到没有唤醒源时就会进入休眠。

如果你想要保持屏幕常亮,Android推荐如下方法(当Activity或view可见时,屏幕才保持常亮),下面代码的效果是相同的:

  1. 在Activity.onCreate()中: getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  2. 在xml布局中: android:keepScreenOn="true"
  3. 对View设置: view.setKeepScreenOn(true);

除了上述方式,我们还可以使用 Wakelock。Wakelock 是阻止系统休眠的接口,我们可以使用它保存屏幕常亮,代码如下:

val wakeLock: PowerManager.WakeLock =
    (getSystemService(Context.POWER_SERVICE) as PowerManager).run {
        newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "MyApp::MyWakelockTag").apply {
            acquire()
        }

    }

使用FLAG_KEEP_SCREEN_ON实际就是一个PowerManager.SCREEN_BRIGHT_WAKE_LOCK级别的WakeLock,它的创建和释放锁都由系统自动管理,更加方便和安全。如果我们向上面的代码一样主动使用wakeLock,一定要记得调用wakelock.release()来释放,最好的做法是要设置超时释放的时间。

还有一种PowerManager.PARTIAL_WAKE_LOCK级别的 wakelock,在这种级别下即使用户按Power键(其它级别的 wakelocks,用户按Power键,系统还是会休眠),系统也不会进入休眠,这种情况一定要特别注意。

这里还补充一下,AlarmManager内部也利用了WakeLock。它是使用系统层级的闹钟服务(持有WakeLock),用来指定时间执行任务:

1.  需要精确的定时任务,如闹钟。

2.  非精准确定时任务,可以推迟任务使多个任务同时执行而避免频繁唤醒系统

3.  网络请求相关的业务不使用AlarmManager

动画

动画相关的例子可以看看大众点评App的短视频耗电量优化实战 - 美团技术团队,写得很好,这里就列一下需要注意的点:

  1. 动画执行需要和Activity的生命周期关联,如果Activity退出前台则需要暂停动画的执行:
  2. onPause之后暂停动画执行,减少CPU耗电;onResume重新开始动画绘制
  3. 当界面的绘制和动画比较复杂或者频繁,优先使用SurfaceView实现,SurfaceView使用单独的绘制线程,避免主线程卡顿

JobScheduler

Job Scheduler作为系统服务运行在系统层面,可以指定运行条件(充电状态、Wifi状态、设备空闲),将收到的任务在合适的时间、状态一起执行。

厂家设备对于 “灭屏 + WIFI + 充电” 的场景管控最为松散,建议可延时的任务、数据埋点上报 放到这里执行。例如:网络请求相关业务放到Job Scheduler执行、一些与特定场景(JobInfo)绑定的任务

UI绘制

UI绘制方面的优化,网上的文章很多,这里就列举一些需要注意的点:

  1. 移除不必要的background,比如window默认或嵌套的background
  2. onDraw多次重复绘制图案,使用clipRect与drawRect
  3. onDraw方法内不要new对象,避免频繁的GC
  4. 使用等优化UI布局
  5. ConstraintLayout替代RelativeLayout、LinearLayout,减少界面测量和布局的次数,优化layout开销
  6. 减少不必要的infalte,使用变量缓存减少资源加载
  7. Listview复用convertView,减少资源加载
  8. 快速滑动列表时,对于图片加载或者网络请求类,在停止滑动才加载数据
  9. clipPath可能导致CPU、GPU占用过大的问题