欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android UI性能优化之Overdraw

程序员文章站 2024-03-17 17:49:22
...

转载自:https://blog.csdn.net/u011693517/article/details/49155965

什么是Overdraw?

Overdraw就是屏幕上某个像素点在同一帧被绘制了多次。在多层布局结构中,不可见部分也会被绘制。举个例子,一个白色页面上有一个按钮。系统首先绘制白色背景,然后在白色背景上绘制按钮,最后在按钮背景上绘制按钮内容。那么按钮和按钮内容就造成了Overdraw。 
其实Overdraw是不可避免的,我们要做的是检查Overdraw次数过多的地方,并删掉无用的绘制。

如何检查Overdraw?

在开发者工具中勾选Show GPU overdraw选项,观察UI上的Overdraw情况。


Android UI性能优化之Overdraw


该工具会以不同的颜色绘制在屏幕上,标识出该块UI的Overdraw情况。


Android UI性能优化之Overdraw


如果是透明色,表示只绘制了一次,没有Overdraw。 
我们要做的就是减少大面积的红色区域,使其变成蓝色甚至是透明色。对于深红色,就要思考出了什么问题,坚决进行优化。

优化菜鸟裹裹物流详情页面

首先打开Show GPU overdraw选项,观察一下情况。


Android UI性能优化之Overdraw


相当恐怖,几乎全是深红色。

分析Overdraw原因

布局结构:基于ListView展示,快递信息、物品信息、小件员信息在同一个View封装,作为HeaderView加入ListView,ListView的item展示物流跟踪信息。


Android UI性能优化之Overdraw

绘制层级:

第一层: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设置整体背景。


Android UI性能优化之Overdraw


优化效果初见成效,满屏的红色没有了,取而代之的是大块的绿色和蓝色,小块淡红色和极少的深红色。

第三步,优化HeaderView

从UI设计来看,HeaderView的几个区块是白色背景,中间用灰色分割。 
原来的实现方案是root view设置灰色背景,sub view使用margin暴露root view底色。如下图:


Android UI性能优化之Overdraw


这里是存在优化空间的,可以将双层结构改为单层,区块之间的分割使用灰色背景的view即可。修改后的结构如下图:


Android UI性能优化之Overdraw


通过布局结构的优化,可以使HeaderView再减少一次Overdraw。

第四步,细粒度优化

观察第二步优化后的情况,可以发现,物品信息TextView和快递图标ImageView还是存在深红色。 
检查布局文件发现,TextView设置了和parent view相同的背景色,这很简单,删除即可。 
快递图标使用了两个ImageView组成,一个展示快递图标,另一个为图标增加了边框。我将两个ImageView进行合并,通过src属性展示图标,background属性设置边框,并增加了1px的padding把边框展示出来。 
而物品图标使用了自定义的ImageView,使用上述优化手段存在bug,暂不做处理。 
至此,优化工作完成,下图是优化后的效果。


Android UI性能优化之Overdraw


可以看出,整屏基本上都是蓝色,少量绿色以及小面积的淡红色,基本达到了优化效果。

最后,总结一下优化步骤

  1. 删除window默认背景。
  2. 删除多层布局结构中重复设置的背景
  3. 优化布局,减少布局层次。
  4. 检查组件,删繁去冗。