前言
在Android进阶之路上, 性能优化是一个绕不开的问题。这部分内容非常考验程序员的内功和项目经验,必须要对Android各功能模块原理和Android系统有个比较全面的了解才能做好这个工作。
本人在前段时间的工作中做过一些优化,现在把这部分内容做个简单的总结,分享给大家。由于时间关系,先简单总结一下,至于各部分的细节,后面再写吧。
我的优化工作主要包含了以下部分:UI优化、内存优化、apk优化、网络优化、多线程、数据存储优化
性能优化.png
一、UI优化
关于UI优化,其实主要是UI卡顿的优化。卡顿本质:Android系统大概每隔16ms会做一次屏幕刷新,如果一次UI渲染不能在这个时间范围内完成,那么将会出现丢帧的现象,从而产生卡顿。
如果面试问了UI卡顿相关的问题,虽然会要求你说一些导致卡顿的原因(过度绘制、布局嵌套太深等),但这只是表象,有经验的面试官可能更多的是想听你讲一下Android屏幕渲染机制,所以这里简单说一下屏幕渲染,更详细的内容可以参考上面几篇文章。
Android屏幕刷新机制简介
首先屏幕系统主要包括CPU、GPU、屏幕显示器三个部分,CPU(中央处理器)主要负责数据计算,GPU(图像处理器)负责图片渲染,屏幕显示器负责最后的显示。Android中的UI绘制逻辑大概是:CPU负责View树的遍历(measure、layout、draw),然后把计算好的数据交给GPU,告诉GPU在屏幕什么位置如何绘制图形,GPU对数据渲染,渲染好后放到buffer里存起来,交给显示器,显示器负责把buffer里面的数据显示到屏幕上。
注意:我们常说的 Android 每隔 16ms 刷新一次屏幕其实是指:底层以固定的频率,比如每 16ms 将 buffer 里的屏幕数据显示出来。但是这不代表就一定会去执行onDraw()方法,onDraw()方法必须要主动触发才会执行,如果没有的话,当下一次刷新信号来临的时候,显示器就拿着buffer里面旧的数据去显示,而不是说去执行View树的重绘。
1.1 View过度绘制
View过度绘制,是指某些像素在同一帧时间内被绘制多次,从而使CPU或GPU负载过重。这个问题很常见,在布局的ViewGroup嵌套中,稍不注意就出现这种问题,检测的话可以打开守旧开发者选项-->Show GPU Overdraw查看。如果出现红色的尽量优化一下,一般不是太深的话不会卡顿的。
1.2 布局嵌套层级太深,无法在16ms内完成渲染
Android的渲染机制还是比较复杂的,但是应用层来说,主要是measure -->layout--->draw流程。UI绘制实际上是遍历View树,View树层级越深,测量布局耗费的时间就越长,那留给draw的时间就可能不够,自然就会出现丢帧卡顿。
建议:
1、尽可能用扁平化的布局ConstraintLayout;
了解使用 ConstraintLayout 的性能优势
2、合理利用include、merge来减少布局层次
1.3 刷新不合理
建议:减少刷新次数、缩小刷新区域;
1.4 频繁触发measure、layout、draw
浪费CPU、GPU
1.5 主线程做了稍微耗时的操作
比如说读取一下SharedPreference、json反序列化,读取一下文件这些,如果累加时间多了也会丢帧。
1.6 GC频繁
短期内大量垃圾对象的创建、回收会导致频繁gc,主要是循环里面创建对象会导致这种现象,还有一种情况,在自定义view的onDraw()方法创建大量对象,如果onDraw()调用频率很快,和循环没什么区别,在里面创建很多对象,就会发生短时间内大量对象创建并释放,于是频繁GC就发生了,内存抖动了,卡了。
二、内存优化
内存优化主要是:内存泄漏、内存抖动、OOM问题。
2.1 内存泄漏
android上的内存泄漏主要是堆内存的泄漏,最常见的就是Activity泄漏。
原因:
jvm角度而言,主要是堆内存泄漏,分配出去堆内存没有及时回收导致;
代码角度而言,不再使用的对象被其它对象所引用,导致它无法及时回收。
案例:
非静态内部类、匿名内部类 Handler、Thread、AsyncTask
单例模式传入Activity对象
观察者模式注册之后,退出页面时没有及时取消观察
资源性对象未关闭,Cursor、File等
WebView泄漏,放在单独进程
Bitmap没有及时回收,最好放在池子
分析工具
Android Studio Profile 、LeakCanary
解决思路
了解对象的gc引用链,在恰当的时机断开引用关系就可以让对象正常回收。
2.2 内存抖动
短时间内大量对象创建并释放,主要是循环里面创建大量对象,会导致频繁GC,然后内存抖动了。
2.3 OOM问题
APP启动进程之后会分配一定的内存空间,每个手机大小不同,如果程序运营期间申请的内存没有及时释放,堆积的越来越多,最好超出这个阀值就会oom,常见的有加载大图,内存泄漏导致。
常见的有:
加载大图,长图;需要对bitmap压缩之后再显示,可以参考一下二次采样;
资源对象使用完了没有及时回收,内存堆积也会oom;
内存泄漏最严重的结果就是oom
apk优化
res资源优化
1、只用一套高清的图片;
2、使用svg图片节省空间,用于小图标;
3、使用webP图片;
4、如果有大量的drawable.xml设置view背景,考虑用代码封装Drawable实现
5、用Lint工具删除无用资源
代码优化
1、使用proGuard 代码混淆工具;
2、避免引入重复的三方库;
3、so文件只用必须的版本
网络优化
连接复用:节省连接建立时间,如开启 keep-alive。
合并请求
减少传输数据的大小:对于post请求,body可以做gzip压缩的,header也可以做数据压缩。返回数据的body也可以做gzip压缩,
异常拦截优化:请求失败、解析异常
断点续传、分片传输、失败重连、Protocol Buffer
总结
app性能优化是一个持续总结、提升的过程;做的事情很多,但是效果不一定很明显,但你仍然需要在项目中重视此类问题。后面会持续更新
参考: