作者:小墙程序员
在应用开发中,耗电是我们需要关注的重点。但是,开始进行耗电优化时,我们常常感到无从下手。这篇文章将介绍耗电优化的相关要点,让我们优化时有一个方向。
传感器
大多数Android设备都内置传感器,如果你的 App 需要使用传感器,记得在不使用时及时取消注册监听,否则会让 app 在后台一直接收数据,造成不必要的耗电。
如上图,谷歌官方文档上写的很清楚。当我们在Activity切到后台后依然会调用传感器,一般来说onPause之后就已经是非业务场景,在 destroy之前都会持续占用传感器,造成不必要的耗电。
其次,注册传感器时,可以选择传感器精度,精度越高耗电也就越多,我们需要根据业务实际需求选择合适的精度,不要盲目追求高精度。
定位
定位从获取方式可以分为两种,主动获取 或 被动定位。主动获取又可以分为 GPS 和 网络定位。
-
GPS_PROVIDER(GPS方式):
- GPS定位,精准度高耗电量大;
- 室内GPS定位基本没用。
- 绝大部分用户默认不开启GPS模块;
- 从GPS模块启动到获取第一次定位数据,可能需要比较长的时间;
-
NETWORK_PROVIDER(网络定位):
网络定位,利用基站和WIFI节点的地址来定位,取决于将基站或WIF节点信息翻译成位置信息的服务器能力;定位快耗电低。
-
PASSIVE_PROVIDER(被动定位):
被动定位,使用系统中其他应用的定位信息。
如果我们开发的 app 使用了定位服务,需要注意:
- 根据使用场景选择定位模式,优先考虑使用网络定位(比如定位城市)
- 前台定位时,界面 onPause 则停止位置更新;后台定位时,根据页务需求控制位置更新时间间隔。
- 如果应用是多模块开发,模块之间应该尽量复用位置信息,不要同时定位
WakeLock
Android 运行在很多移动设备上,考虑到功耗原因,引入了 autoSleep的休眠方式,当检测到没有唤醒源时就会进入休眠。
如果你想要保持屏幕常亮,Android推荐如下方法(当Activity或view可见时,屏幕才保持常亮),下面代码的效果是相同的:
- 在Activity.onCreate()中:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- 在xml布局中:
android:keepScreenOn="true"
- 对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的短视频耗电量优化实战 - 美团技术团队》,写得很好,这里就列一下需要注意的点:
- 动画执行需要和Activity的生命周期关联,如果Activity退出前台则需要暂停动画的执行:
- onPause之后暂停动画执行,减少CPU耗电;onResume重新开始动画绘制
- 当界面的绘制和动画比较复杂或者频繁,优先使用SurfaceView实现,SurfaceView使用单独的绘制线程,避免主线程卡顿
JobScheduler
Job Scheduler作为系统服务运行在系统层面,可以指定运行条件(充电状态、Wifi状态、设备空闲),将收到的任务在合适的时间、状态一起执行。
厂家设备对于 “灭屏 + WIFI + 充电” 的场景管控最为松散,建议可延时的任务、数据埋点上报 放到这里执行。例如:网络请求相关业务放到Job Scheduler执行、一些与特定场景(JobInfo)绑定的任务
UI绘制
UI绘制方面的优化,网上的文章很多,这里就列举一些需要注意的点:
- 移除不必要的background,比如window默认或嵌套的background
- onDraw多次重复绘制图案,使用clipRect与drawRect
- onDraw方法内不要new对象,避免频繁的GC
- 使用等优化UI布局
- ConstraintLayout替代RelativeLayout、LinearLayout,减少界面测量和布局的次数,优化layout开销
- 减少不必要的infalte,使用变量缓存减少资源加载
- Listview复用convertView,减少资源加载
- 快速滑动列表时,对于图片加载或者网络请求类,在停止滑动才加载数据
- clipPath可能导致CPU、GPU占用过大的问题
为了帮助到大家更好的全面清晰的掌握好性能优化,准备了相关的核心笔记(还该底层逻辑):https://qr18.cn/FVlo89
性能优化核心笔记:https://qr18.cn/FVlo89
启动优化
内存优化
UI优化
网络优化
Bitmap优化与图片压缩优化:https://qr18.cn/FVlo89
多线程并发优化与数据传输效率优化
体积包优化
《Android 性能监控框架》:https://qr18.cn/FVlo89
《Android Framework学习手册》:https://qr18.cn/AQpN4J
- 开机Init 进程
- 开机启动 Zygote 进程
- 开机启动 SystemServer 进程
- Binder 驱动
- AMS 的启动过程
- PMS 的启动过程
- Launcher 的启动过程
- Android 四大组件
- Android 系统服务 - Input 事件的分发过程
- Android 底层渲染 - 屏幕刷新机制源码分析
- Android 源码分析实战