开头简单介绍一下overdraw,过度绘制。
这是一个android ui性能优化一个老生常谈的问题。指的是一帧的时间之内,同一个像素频繁地绘制。他会造成:
- 占用不必要的GPU和CPU资源
- 界面掉帧
OK,现在手机的性能也比较好了,怎么准确知道哪儿overdraw了呢。
Where?
打开手机的开发者权限
,同时在下方能找到调试GPU过度绘制
的选项。
- 蓝色: 意味着overdraw 1倍。像素绘制了两次。大片的蓝色还是可以接受的(若整个窗口是蓝色的,可以摆脱一层)。
- 绿色: 意味着overdraw 2倍。像素绘制了三次。中等大小的绿色区域是可以接受的但你应该尝试优化、减少它们。
- 浅红: 意味着overdraw 3倍。像素绘制了四次,小范围可以接受。
- 暗红: 意味着overdraw 4倍。像素绘制了五次或者更多。这是错误的,要修复它们。
顺带偷偷一提,打开wx你会发现一页红...打开QQ却只有下方tab是红色的.
如何避免?
说白了,overdraw就是同一个像素点绘制了太多次了,这种重复劳动是不必要的。
1. 减少Layout层级
最想到的肯定是减少UI控件的层级,提高RelativeLayout的使用优先度。毕竟RelativeLayout可以完成任意复杂度的布局,他的表达能力是AndroidLayout4大布局里表现能力最强的。但是也有需要注意的地方:
- 相比LinearLayout,RelativeLayout的强表达能力是基于性能上的牺牲,LinearLayout的易用性以及高效的特点依旧无法被取代,我们需要去衡量这两者之间的使用场景。
2. 去除Windows的默认背景
-
Android自带的主题会有一个默认的背景,这个背景是由Decorview(根布局)来进行管理的,会产生一次overdraw,如果你使用了自定义背景,就可以在
setContentView
方法之后,将背景置空:getWindow().setbackgroundDrawable(null);
-
在开发过程中,必要时才给控件添加背景,以免产生一层overdraw。甚至可以将背景置为透明色:
@android:color/transparent
3. 自定义控件优化
-
Android在绘制布局的时候会避免绘制一些不必要不可见的控件以减少overdraw,这算是Android自带的一些优化机制。但是,我们在自定义控件以后,重写了
onDraw
方法,使得Android无法自动识别当前控件的优化逻辑。这时候就需要我们手动去赋予优化逻辑了。 -
这就要提到裁剪画布的方法
canvas.clipRect()
,这个方法可以将我们界面不需要显示的控件裁掉以达到减少控件重叠,节约GPU资源的效果。 -
除了clipRect方法之外,我们还可以使用
canvas.quickreject()
来判断是否没和某个矩形相交,从而跳过那些非矩形区域内的绘制操作
4. ViewStub 高效占位符
-
在布局时需要一些控件在需要的时候再显示出来。这时候我们常规的做法就是
new
一个控件,或者,设置控件的visiblity
属性为View.GONE
或者View.INVISIBLE
这个两个属性使得控件暂时不可见。这种做法虽然逻辑简单,但是在控件显示时会创建对象,需要实例化,加载资源,是比较损耗内存的。 -
这时候常规的做法是使用Android.view.ViewStub.他是一个View的占位符。在界面初始化时,他已经将控件的对象实例化,只不过这个对象耗费的资源非常小,非常轻量。然后在控件显示时,会进行
imflate
操作,并不会重新创建对象,对于内存的损耗就降低了。
5. merge标签
- 这个标签就比较常用了。和
<include>
配合使用以期得到布局复用的效果算是比较常见的用法。这个标签的作用就是干掉一个层级。
6. 减少使用Alpha
-
如果一个view要进行Alpha化,首先他需要生成view,这是一个层级,之后再做Alpha,这就形成了二次加载overdraw,时间和内存损耗双倍增加了。所以这玩意儿慎用。
-
一定做Alpha转化的话,可以采用缓存的方式。
通过setLayerType方式可以将当前界面缓存在GPU中,这样不需要每次绘制原始界面,但是GPU内存是相当宝贵的,所以用完要马上释放掉。
网友评论