OverDraw就是在某个像素点同一帧内被绘制了多次。最优情况是一个像素每次只被绘制一次。
在多层布局中,不可见部分也会被绘制,这就产生了额外开销。
OverDraw是不可避免的!我们需要做的是将OverDraw过多的部分去掉,删掉一些无用的绘制,尽量优化。
Android提供了工具
在开发者选项---硬件加速渲染---调试GPU过度绘制
工具会标识出OverDraw的情况
透明--->没有overdraw。完美。
蓝色--->1倍overdraw。绘制两次。可以忍。大面积的话,考虑是否可以干掉一层。
绿色--->2倍overdraw。绘制三次。面积不大的绿色区域可以忍。可尝试优化。
浅红--->3倍overdraw。绘制四次,面积小的浅红可以忍。一般就是写文字按钮什么的。
暗--->4倍及以上overdraw。绘制五次或更多。不能忍!!!肯定可以优化!
避免绘制不可见元素!(OverDraw就是一个像素画多了)
一. 优化Layout的布局结构
1. layout提倡扁平化,层级越少性能越好。
2. 层级一样,控件数一样,优先选择LL。(不过,这种小的优化,只有在层级高的时候才会有体现;可惜高层级本来就要规避。)
3. 利用merge去分割一些layout。Merge会沿用他的父viewlayout的,本身并没有多一层。
二. 去掉window的默认背景
在某些Theme会有默认的黑色背景,如果是Light,可能是白色背景。这也是一个图层。DecorView会持有这个background,而一般是无用的。
Activity的onCreate方法中,调用getWindow().setBackgroundDrawable(null)即可删除这个默认背景。
注意.这个方法应该在setContentView之后调用。
上一段源码解析:Activity的setContentView最终会调用到PhoneWindow.java的setContentView.
@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
......
}
继续看installDecor()如何实现
private void installDecor() {
......
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
......
if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
mDecor.setBackgroundFallback(mBackgroundFallbackResource);
}
......
}
}
可以看到mDecor会setBackgroundFallback。所以,如果在setContentView之前调用getWindow().setBackgroundDrawable(null)是无效的。必须在setContentView之后。
三. 针对系统自带widget-简化没必要的背景
举例来说,一些ListView是fill_parent的,而有时候为了方便又为容器控件设置了background.这就造成了overdraw。同样如果有一些没必要的TextView有这样的重复layout也是需要剔除的。还有一些Button。在Normal状态可以沿用底层background,或者底层background根本不需要。通过selector将normal的background设置为@android:color/transparent
四. 针对自定义onDraw的View--ClipRect
对于过于复杂的自定义View,Android系统无法检测具体onDraw执行了什么,就无法监控并自动优化。
1. 我们可以用canvas.clipRect制定一块需要被绘制的区域。其他区域就会被忽略。
2. 还可以用canvas public boolean quickReject(Rect r)来判断是否没和某矩阵相交
先看一张图
是不是一下子就少了很多需要绘制的区域。
五. 利用draw9patch
Andrid的2D渲染会优化.9的图片的透明部分。所以偶尔有大图片的时候,这不仅可以减小apk大小,还可以减少overdraw。
六. 慎用Alpha变化
alpha变化包括两个操作
1. 先绘制出不透明的View
2. 进行alpha变化
这就是两次的绘制。要尽量避免。不过有时候拗不过产品,注意一些延迟触发的方法,比如ViewStub,这种高效占位符还是比较好使的。延迟绘制。
七. 警惕过度设计
华丽的设计基本上就是Overdraw的创造者。你懂的。无解。不过可以据理力争。再牛逼的开发都抵不过超复杂的产品