Android UI性能优化之Overdraw
转载自:https://blog.csdn.net/u011693517/article/details/49155965
什么是Overdraw?
Overdraw就是屏幕上某个像素点在同一帧被绘制了多次。在多层布局结构中,不可见部分也会被绘制。举个例子,一个白色页面上有一个按钮。系统首先绘制白色背景,然后在白色背景上绘制按钮,最后在按钮背景上绘制按钮内容。那么按钮和按钮内容就造成了Overdraw。
其实Overdraw是不可避免的,我们要做的是检查Overdraw次数过多的地方,并删掉无用的绘制。
如何检查Overdraw?
在开发者工具中勾选Show GPU overdraw选项,观察UI上的Overdraw情况。
该工具会以不同的颜色绘制在屏幕上,标识出该块UI的Overdraw情况。
如果是透明色,表示只绘制了一次,没有Overdraw。
我们要做的就是减少大面积的红色区域,使其变成蓝色甚至是透明色。对于深红色,就要思考出了什么问题,坚决进行优化。
优化菜鸟裹裹物流详情页面
首先打开Show GPU overdraw选项,观察一下情况。
相当恐怖,几乎全是深红色。
分析Overdraw原因
布局结构:基于ListView展示,快递信息、物品信息、小件员信息在同一个View封装,作为HeaderView加入ListView,ListView的item展示物流跟踪信息。
绘制层级:
第一层:window背景
第二层:Activity中fragment container背景
第三层:Fragment中ListView背景
第四层:ListView的Header背景和物流信息item背景
第五层:快递信息、物品信息、小件员信息背景和物流信息item内容
第六层+:快递信息、物品信息、小件员信息内容
开始优化
第一步,删除window默认背景
Android系统提供了默认的背景,被DecorView持有,但是通常情况,我们会为全屏提供自定义颜色,那么这个背景就没用了,反而会带来一次Overdraw的性能损耗。
Activity的onCreate方法中,调用getWindow().setBackgroundDrawable(null)即可删除这个默认背景。
注意,这个方法应该在setContentView后调用。原因通过分析源码可知:
setContentView通过调用PhoneWindow的setContentView,再到installDecor。最终通过以下代码设置背景:
if (mDecor.getBackground() == null &&mBackgroundFallbackResource != 0) {
mDecor.setBackgroundFallback(mBackgroundFallbackResource);
}
而getWindow().setBackgroundDrawable(null)同样会调用PhoneWindow的以下方法:
public final void setBackgroundDrawable(Drawable drawable) {
if (drawable != mBackgroundDrawable || mBackgroundResource != 0) {
mBackgroundResource = 0;
mBackgroundDrawable = drawable;
if (mDecor != null) {
mDecor.setWindowBackground(drawable);
}
if (mBackgroundFallbackResource != 0) {
mDecor.setBackgroundFallback(drawable != null ? 0 : mBackgroundFallbackResource);
}
}
}
可以看出,如果先调用getWindow().setBackgroundDrawable(null), setContentView会再次设置背景色。
因此,getWindow().setBackgroundDrawable(null)应该在setContentView之后调用。
第二步,删除布局中重复设置的背景
整个布局基于ListView全屏展示,因此和Activity中fragment container背景冲突,保留其中之一即可,在这里选择删除ListView的背景,由container设置整体背景。
优化效果初见成效,满屏的红色没有了,取而代之的是大块的绿色和蓝色,小块淡红色和极少的深红色。
第三步,优化HeaderView
从UI设计来看,HeaderView的几个区块是白色背景,中间用灰色分割。
原来的实现方案是root view设置灰色背景,sub view使用margin暴露root view底色。如下图:
这里是存在优化空间的,可以将双层结构改为单层,区块之间的分割使用灰色背景的view即可。修改后的结构如下图:
通过布局结构的优化,可以使HeaderView再减少一次Overdraw。
第四步,细粒度优化
观察第二步优化后的情况,可以发现,物品信息TextView和快递图标ImageView还是存在深红色。
检查布局文件发现,TextView设置了和parent view相同的背景色,这很简单,删除即可。
快递图标使用了两个ImageView组成,一个展示快递图标,另一个为图标增加了边框。我将两个ImageView进行合并,通过src属性展示图标,background属性设置边框,并增加了1px的padding把边框展示出来。
而物品图标使用了自定义的ImageView,使用上述优化手段存在bug,暂不做处理。
至此,优化工作完成,下图是优化后的效果。
可以看出,整屏基本上都是蓝色,少量绿色以及小面积的淡红色,基本达到了优化效果。
最后,总结一下优化步骤
- 删除window默认背景。
- 删除多层布局结构中重复设置的背景
- 优化布局,减少布局层次。
- 检查组件,删繁去冗。