Android UI优化之OverDraw

OverDraw定义

OverDraw就是在某个像素点同一帧内被绘制了多次。最优情况是一个像素每次只被绘制一次。
在多层布局中,不可见部分也会被绘制,这就产生了额外开销。
OverDraw是不可避免的!我们需要做的是将OverDraw过多的部分去掉,删掉一些无用的绘制,尽量优化。

OverDraw检测

Android提供了工具
在开发者选项---硬件加速渲染---调试GPU过度绘制

Android UI优化之OverDraw_第1张图片

工具会标识出OverDraw的情况

 Android UI优化之OverDraw_第2张图片

透明--->没有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之后调用。
上一段源码解析:ActivitysetContentView最终会调用到PhoneWindow.javasetContentView.
    @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)来判断是否没和某矩阵相交
  先看一张图
  Android UI优化之OverDraw_第3张图片
  是不是一下子就少了很多需要绘制的区域。

. 利用draw9patch
  Andrid的2D渲染会优化.9的图片的透明部分。所以偶尔有大图片的时候,这不仅可以减小apk大小,还可以减少overdraw。

. 慎用Alpha变化
  alpha变化包括两个操作
  1. 先绘制出不透明的View
  2. 进行alpha变化
  这就是两次的绘制。要尽量避免。不过有时候拗不过产品,注意一些延迟触发的方法,比如ViewStub,这种高效占位符还是比较好使的。延迟绘制。

. 警惕过度设计
  华丽的设计基本上就是Overdraw的创造者。你懂的。无解。不过可以据理力争。再牛逼的开发都抵不过超复杂的产品

Android UI优化之OverDraw_第4张图片

你可能感兴趣的:([android])