性能优化02-布局优化
一、CPU与GPU
1、定义
为什么要了解CPU与GPU呢?因为布局绘制就是CPU与GPU实现的。
CPU:负责把布局文件加载到内存中,然后计算所有控件的位置和大小等,得到向量图形。
GPU:负责对CPU传来的向量图形层层渲染,即栅格化填充。
显示器:负责将GPU渲染的图形显示出来。
2、GPU缓冲机制
GPU缓冲机制是指缓存CPU传来的向量图形。
CPU计算布局文件的过程是很耗时的,而实际项目中经常会用到相同的布局文件,这个时候缓冲就有必要了。
3、绘制时间
绘制时间是指CPU开始加载布局文件到GPU完成渲染的时间。
绘制时间由xml文件的复杂程度决定。
4、卡顿分析
我们知道,手机显示器每隔16ms刷新一次屏幕。
那为什么是16ms呢?因为16ms一个画面即60fps,低于60fps,用户就会感觉卡顿。
如果屏幕刷新的时候,绘制没有完成,那么就要等16ms后才能显示,而不是绘制完成就显示。这个时候,就会出现丢帧,用户会感觉卡顿。
二、布局优化
布局是指xml文件和自定义控件。
布局文件越复杂,绘制时间就越长,就越容易卡顿。
那么怎么优化布局呢?
- 减少布局层数
- 减少过度绘制
- 减少控件数量
1、减少布局层数
要减少布局层数,先要查看布局层数。这里使用Hierarchy Viewer工具。
怎么减少布局层数呢?
常用的办法:Relativelayout布局、merge标签、viewStub标签、include标签
Hierarchy Viewer
使用:通过ddms工具打开。
说明:每个view包含Measure, Layout和Draw
颜色:
- 绿: 表示该View的此项性能比该View Tree中超过50%的View都要快;例如,代表Measure的是绿点,意味着这个视图的测量时间快于树中的视图对象的50%。
- 黄: 表示该View的此项性能比该View Tree中超过50%的View都要慢;
- 红: 表示该View的此项性能是View Tree中最慢的;。
绘制时间:点击三色圆圈,即可显示加载时间。布局越复杂,等待显示时间越长。
Relativelayout布局
Relativelayout布局相比Linearlayout布局,更加灵活,但是性能要低。
如果使用Linearlayout布局时,布局层数太多,就需要使用Relativelayout布局。
merge标签
merge标签在布局文件中会包含子控件,但是实际绘制时会被忽略,从而减少布局层数。
注意:自定义控件不能替换为merge。
viewStub标签
只有设置viewstub为visible、invisible或者调用其inflate()方法时,才会进行绘制。
用法:
<ViewStub
android:id="@+id/vs"
android:layout="@layout/viewstub"
android:layout_width="match_parent"
android:layout_height="match_parent" />
局限性:
- viewstub的引用对象必须是一个layout文件,不能是单个View;
- ViewStub在加载完引用的layout后会被移除,所以只能加载一次。
include标签
include标签实际上不能减少布局层数,但是还是能提升性能。
使用include的布局一般会重复使用,由于GPU缓冲机制,所以不会重复CPU计算的过程,从而提升性能。
2、减少过度绘制
过度绘制是指布局渲染的层数过多。需要说明的是,布局的层数多并不一定渲染层数就多。因为容器的背景如果为空,就不会进行渲染。
那怎么检查是否出现过度绘制呢?使用手机端的GUP过度绘制工具。
出现过度绘制后,如何减少过度绘制呢?
- xml文件减少重复背景
- 自定义控件减少重叠绘制
GUP过度绘制工具
使用:开发者选项-调试调试过度绘制,打开即可。
颜色:
- 白色:没有过度绘制
- 浅蓝:1层过度绘制
- 绿色:2层过度绘制
- 浅红:3层过度绘制
- 红色:4层过度绘制
xml文件减少重复背景
-
theme背景与activity背景
theme都有一个默认背景,每个activity也会设置一张背景。因为activity背景会覆盖theme背景,但是GPU渲染的时候,还是会渲染theme背景,所以要把theme背景设为空。
-
容器背景
如果容器背景与父容器背景相同,就要把容器背景设为空,避免重复渲染。
自定义控件减少重叠绘制
一张画布上包含多个bitmap,并且这些bitmap出现重叠时,就会出现重叠绘制。因为GPU渲染时,会把每个bitmap完全渲染出来,虽然有些被覆盖了。
怎么减少重叠绘制呢?
通过Canvas.clipRect()对画布进行裁剪,裁剪出bitmap要显示的大小,这样GPU渲染时就只渲染要显示的部分。裁剪完,需要调用Canvas.restore()还原画布,让下一个bitmap使用。
3、减少控件数量
这个要从逻辑上调整,这里就不分析了。











网友评论