前言
- App优化 - 需要优化哪些?
- App优化 - 性能分析工具
- App的3种启动方式
- App优化 - App启动速度优化
- App优化 - 布局优化
- App优化 - 消除卡顿优化
- App优化 - ANR优化
- App优化 - 电池省着用
- App优化 - 网络优化
1. 感知卡顿
用户之所以会感觉到卡顿,是界面刷新的原因,界面性能取决于UI渲染性能,如果UI过于复杂,或者实现不够好,设备也不给力,界面就会卡顿,给用户卡顿的感觉。
1.1>:16ms原则?
Android系统每隔16ms会发出 vsync信号,重绘界面(Activity);
1.2>:16ms原因?
因为Android的刷新率是60FPS(Frame Per Second),即就是每秒60帧的刷新率,约16ms刷新一次,如下图所示;
上图意思就是:
每隔16ms重绘一次Activity界面,每隔16ms重绘一次Activity界面,每隔16ms重绘一次Activity界面;
也就是说我们需要在16ms之内要完成下一次刷新界面的所有相关的运算和操作,来重绘解Activity界面,如果16ms没有完成需要刷新界面的 相关运算和操作,就会导致丢帧、用户感觉界面卡顿,如果界面过于复杂,丢帧会更多,卡到爆。
1.3>:举例
1>:比如我们更新屏幕背景图片,需要24ms来完成运算和操作,当系统在第一个16ms刷新Activity界面时,因为还没运算完,所以不能绘制出图片,当系统下一次再发出 vsync信号重绘界面时,可以重绘界面,用户能看到更新后的图片,也就是说32ms后看到刷新而不是24ms,这个叫做丢帧;
2>:丢帧给用户感觉就是卡顿,如果运算复杂,丢帧会更多,界面会停滞不前,卡到爆;
2. 卡顿原因?
2.1:布局过于复杂
界面性能取决于UI渲染性能,UI渲染由CPU和GPU两个部分共同完成;
CPU处理内存,负责执行onMeasure()、onLayout()、onDraw()等一些运算;
GPU处理界面,负责将UI绘制到界面上;
如果UI布局层次太深,或者自定义View中的onDraw()方法有复杂的计算,CPU运算可能大于16ms,导致卡顿;
可以使用Hierarchy Viewer工具分析布局,以图形化树状结构展示UI层级,会对每个节点给出三个小圆点,表示该元素的onMeasure()、onLayout()、onDraw()的耗时及性能;
2.1:过度绘制(Overdraw)
定义: overdraw:同一个像素点被绘制多次
理想情况是,每一个界面中每一帧,每一个像素点,应该只能被绘制一次,如果有多次绘制,就是Overdraw过度绘制了;
2.1:调试Overdraw
手机 -> 开发者选项 -> 调试GPU过度绘制,有5种颜色:
原色:没有被绘制overdraw;
蓝色:只绘制1次overdraw;
绿色:绘制2次overdraw;
粉色:绘制3次overdraw;
红色:绘制4次overdraw;
一般是:蓝色性能比较优的;
2.2:Overdraw的分析
常见就是:
1>:绘制多重布局
在xml布局文件中,background属性在根布局和子布局中重复设置
举例如下:
中间的ViewPager设置了background属性:
ViewPager所在的根布局的也设置了background属性:
...
解决方法就是:这两个background属性任意去掉一个就可以,因为两个background同时都给ViewPager设置了背景,所以需要去掉一个,效果如下:
注意:
过度绘制overdraw主要原因就是背景多重绘制。多重绘制原因就是在根布局及子布局中多次使用同一个background属性,一般建议把background属性写到 根布局中就ok,这样就可以避免 过度绘制overdraw。
2.3:UI线程的复杂运算
StrictMode:基于线程或者VM设置的策略,用于检测主线程的磁盘读写、网络访问等耗时操作;一旦检测到线程违例,控制台就会输出一些警告,包含一个trace信息,它会展示你的应用在什么地方出现的问题;
用法:
在BaseApplication中的onCretate()中开启 StrictMode:
public void onCreate() {
if (BuildConfig.DEBUG) {
// 针对线程的相关策略
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork() // or .detectAll() for all detectable problems
.penaltyLog()
.build());
// 针对VM的相关策略
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.penaltyDeath()
.build());
}
super.onCreate();
}
注意:
如果线程出现问题,会在控制台输出警告,能定位到具体代码
2.4:频繁的GC原因?
执行GC操作的时候,任何线程的任何操作都会需要暂停,等GC操作完之后其他操作才可以进行,所以说频繁的GC会导致界面卡顿
导致频繁的GC有2个原因:
1>:内存抖动:大量对象被创建,又在短时间内马上释放;
2>:瞬间产生大量对象,会严重占用Young Generation内存。当达到阈值,剩余空间不够时,也会触发GC。即使每次分配的对象需要占用很少的内存,但它们叠加在一起会增加Heap的压力,从而触发更多的GC,结果就是可能造成丢帧,会让用户感受到卡顿;
瞬间产生大量对象的场景:
1>:循环new对象;
2>:onDraw()方法中new对象;