移动性能测试 Android 过度绘制简单分析

saii · 2016年01月17日 · 最后由 天荧 回复于 2016年02月18日 · 7715 次阅读
本帖已被设为精华帖!

概念

当 android 系统绘制屏幕的时候,先画父 view,然后子 view,再是更深的子 view 等等。这会导致所有的 view 都被绘制到了屏幕上并且这些 view 都被他们的子 view 覆盖住了。
在 Debug GPU overdraw 菜单里选择 “Show Overdraw areas” 选项。选择之后,会在 app 的不同区域覆盖不同的颜色来表示 overdraw 的次数。比较屏幕上这些不同的颜色,可以快速方便的定位 overdraw 问题:
白色:没有 overdraw
蓝色:1x overdraw
绿色:2x overdraw
浅红色:3x overdraw
深红色:4x 或者更多 overdraw

以上就是过度绘制的概念。光知道这些当然是没什么作用的,还是需要结合实际的例子才能够懂得一些。

对比分析

很简单我们拿我们 Testerhome的 app 来简单的分析下。
我们开启 GPU 过渡绘制后,查看界面

这里写图片描述

  • banner 区域的多重绘制可以理解,因为确实是需要在 viewpager 上面重新绘制一个 textview
  • recyclerview 中显示红色就有点难以理解了。

当然我们比较下我们熟悉的微信吧。

这里写图片描述

很明显微信上面是没有这个问题的。既然发现问题,我们就来分析下到底是什么导致了这个现象吧,我们从 github 上拉下最新的的代码A-Native-TesterHome, 我们需要理解一点,过渡绘制导致的原因基本是父类的布局设置了一个背景,子类的布局又重新在上面绘制了一层。
我们进入到list_item_topic.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:fresco="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rl_topic_item"
    android:background="@drawable/item_selector"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="8dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="8dp">

    <com.facebook.drawee.view.SimpleDraweeView
        android:id="@+id/sdv_topic_user_avatar"
        android:layout_width="56dp"
        android:layout_height="56dp"
        android:layout_marginRight="16dp"
        fresco:roundAsCircle="true" />

以上我们可以发现 RelativityLayout 中设置了 background 了,从名字我们也能够看出了这个是在 item 被选中的时候,能够显示出被选中的状态。具体:
a

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/item_selected_drawable" android:state_pressed="true" />
    <item android:drawable="@color/white" />
</selector>

那么我们能够修改吗 ? 当然我们肯定不能够直接把 background 注释掉,因为那样子就没有点击的效果了。我们可以把尝试把 default 的注释掉,也就是:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/item_selected_drawable" android:state_pressed="true" />
    <!--<item android:drawable="@color/white" />-->
</selector>

下来我们来看看修改后的结果吧

这里写图片描述

嗯。问题看来就是这么解决的了

本来想通过 hierarchyviewer 看看修改前后绘制需要的时间,结果试了下发现没什么变化。估计是我的使用方法不正确。这里就不献丑来。

参考文章

Android UI 性能优化详解

强烈推荐看这篇文章,干货多。

PS:以上这个只是简单的一个过度绘制修改,当然还有通过 hierarchyviewer 来简化一些布局等等。

2.27 号更新:
其实回过头来看看,其实前面的改法不太对,应该最终的改法时去掉默认的背景颜色
即在

setContentView(R.layout.activity_main);
//添加下面这句
getWindow().setBackgroundDrawable(null);
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 15 条回复 时间 点赞

赞,还加了实践。。

感谢分享~

实例最棒了

参考文章很好. 作者还分享了抓取微信红包图片的过程, 蛮好.

好棒。。用这个试了一下我们公司的 App,基本都是红色的。。我要不要做点什么。。

saii #7 · 2016年01月28日 Author

#6 楼 @m13890 找熟悉的开发,跟他谈谈,推动问题解决。

#7 楼 @zsx10110 哈哈,沟通过了,他们决定无视。我看了下代码,发现其实就是和你的例子是差不多的情况。

参考链接貌似挂了,另外找到了这个:http://www.cnblogs.com/dongweiq/p/5144186.html

你看是不是一样的?

saii #6 · 2016年02月14日 Author

#9 楼 @chenhengjie123 嗯 是的,我把原文的链接也替换一下吧。 谢

Testerhome 的 app recyclerview 中显示红色会不会是因为要标志文章已读

saii #12 · 2016年02月15日 Author

#11 楼 @isobel 哪里显示红色,不太明白?

@zsx10110 你的原文中就有这么一句话 “recyclerview 中显示红色就有点难以理解了。”

saii #14 · 2016年02月15日 Author

#13 楼 @isobel 哦! 我的意思就是说在 recyclerview 中出现红色就说明不正常的现象,存在过度绘制。

赞 好

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册