EN

Android 性能优化之过度绘制 - 实战篇

字数统计: 2.5k阅读时长: 8 min
2015/01/13
loading

前言

上一篇文章从理论的角度讲解了一下什么是过度绘制,以及可以用来查看和确认过度绘制的工具,还提供了一些优化过度绘制的方法。对代码和布局比较熟悉的人,看完上一篇其实就已经可以对自己的应用进行优化了。我记得有人说过,用iphone你只需要保证苹果有节操即可,用Android你就得保证所有的Android开发者都有节操。但现实是残酷的,现在Android市场上,有很多粗制滥造的应用,其中不乏大厂之作,各位打开过度绘制按钮,就知道我所言非虚。作为一个Android开发人员,我肯定是更希望Android能一步一步好起来,超越iphone。

这篇文章从实战的角度,讲解了一个过度绘制的优化过程。当然这里用到的只是很少的一部分,毕竟每个应用差别很大,优化方式也各不一样。所以这篇文章仅供参考,想把这块做好还是要下功夫的。

如果没有看过前一篇,可以点这里:Android性能优化之过度绘制(一)


技术复核(2026-10-13):本文记录的是 2015 年文件管理器的优化过程,设备系统和应用的精确版本未保留。Monitor、Hierarchy Viewer、Tracer for OpenGL ES 的操作步骤已过期:Android Device Monitor 在 Android Studio 3.1 弃用、3.2 移除。下面保留当年的截图和排查过程;颜色变化只能说明这些画面中的重复绘制减少,原文没有帧耗时数据,不能据此推断帧率或功耗改善。

现在排查 View 页面,可以用 Android Studio Layout Inspector 确认运行时层级与背景,再用 Debug GPU Overdraw 找重复绘制区域。性能对比要在同一设备、同一系统和同一交互条件下进行,关闭调试着色后采集 System Trace。Android 12 / API 31 及以上还可查看 Perfetto FrameTimeline;该数据源目前不支持 SurfaceView,不能把它当作所有画面的通用测量入口。

定位过度绘制区域

打开 GPU 过度绘制选项

在开发者选项中找到“调试 GPU 过度绘制”,选择“显示过度绘制区域”。原机型的入口位于“设置—辅助功能—开发人员工具—硬件加速渲染”;其他系统的菜单位置可能不同。

打开待测页面

开启调试着色通常不要求先杀掉应用。下面是当年重新打开文件管理器和设置后的截图;正式做前后对比时,应固定冷启动或热启动条件,以及列表内容、展开状态等,避免把不同状态的差异算作优化效果。

文件管理器设置

在这组截图采用的默认配色中,蓝、绿、浅红、红分别表示额外绘制 1 次、2 次、3 次、4 次及以上。文件管理器有较大面积的绿色和红色,值得继续检查。设置页面可以帮助理解配色,但两者的内容和功能不同,不能用设置页面的颜色给文件管理器划定性能合格线。

从文件管理器的图分析可疑区域

  • ActionBar 和底部 SmartBar 大片呈蓝色,说明有额外绘制;主题背景是一个排查方向。但颜色本身无法指出是哪一个 View 或 Drawable 在画,仍需核对层级、背景属性和代码。
  • 中间内容的大面积绿色表示两次额外绘制。如果其中有被不透明内容完全覆盖的背景,就可能有删减空间;“与设置页面颜色不同”并不足以证明背景多余。
  • 先定位这些大面积区域,再检查局部图标、列表项和滑动菜单。

优化过度绘制区域

当年的操作是打开 Monitor,在右上角切换到 Hierarchy View,逐层查看 View。下面的截图保留了这一步;现在应使用 Layout Inspector。

Hierarchy View

图中的根节点是 PhoneWindow$DecorView,其下是 ActionBarOverlayLayout。这是当年机型与主题下的实际层级,不代表所有 Android 应用都具有同样的结构。层级图能帮助定位控件,但不能仅凭父子关系判断窗口背景属于 ActionBarOverlayLayout。

去除被完全遮挡的背景

先区分 Window 的背景和各个 View 自己的背景。我当时在文件管理器主 Activity 的 onCreate() 中加了下面这行代码:

1
getWindow().setBackgroundDrawableResource(android.R.color.transparent);

它把窗口背景替换为透明颜色 Drawable,并非移除了 Drawable 对象。对于内容始终完整、不透明地覆盖窗口的页面,可以评估使用 API 1 就提供的 getWindow().setBackgroundDrawable(null);它也不等同于把窗口设为透明。无论采用哪种做法,都要检查加载、空列表、菜单滑动和页面切换等状态,确认没有露底或闪烁。不能把这行代码当成所有 Activity 的固定优化。

原文使用透明背景后的截图如下,一张是菜单展开,一张是未展开:

文件管理器文件管理器

对比前面的图,ActionBar 上的蓝色消失了,中间内容也从绿色变成蓝色,这些区域少了一次重复绘制。

消除子控件的多余背景

继续查看中间内容对应的 DragRelativeLayout。按当年的源码记录,它继承自项目使用的 SlidingMenu,由 CustomViewAbove 和 CustomViewBehind 组成:前者承载可左右移动的内容,后者承载其后的菜单。

Hierarchy View

打开 CustomViewBehind 的代码,我在构造函数里找到了这行背景设置:

1
setBackgroundColor(getResources().getColor(R.color.mz_slidingmenu_background_light));

当时的判断是:SlidingMenu.setMenu() 添加的菜单内容已经完整覆盖了这个背景。因此删掉的是父容器的背景绘制,不是删除 CustomViewBehind 这个 View。这个结论依赖该项目的具体实现,不能直接套到同名开源控件或其他版本上;尤其要检查菜单展开后的空白区域是否仍需要父背景。

下面是当时删除这层背景后的截图:

文件管理器文件管理器

图中多个区域的重复绘制继续减少,后续仍需要核对菜单展开与收起时的实际外观。

进一步检查列表项

接着往下看,CustomViewAbove 里有一个 ID 为 FilesList 的 ListView。我当时试着去掉了 PartitionItemLayout.onDraw() 里的 setBounds() 调用,过度绘制的颜色少了,但列表项的颜色也变浅了。下面是那次尝试的截图:

文件管理器文件管理器

列表项变浅这件事不能忽略,这一步还不能算优化成功。Drawable.setBounds() 只是设置后续 draw() 的绘制范围,本身不执行绘制。删掉它,可能会让 Drawable 沿用错误边界,甚至把本来需要的背景也弄没了。

还得找到实际画背景的调用,确认这层背景多余,再删除或缩小绘制范围,保持原本要求的外观。蓝色仍代表一次额外绘制,颜色变少也不等于渲染路径已经“最优”。


优化代码

Lint 工具

Lint 和 IDE 检查能提示冗余布局、未使用资源和潜在错误,但是否修改仍取决于上下文。下面的例子提示 FrameLayout 或其父布局可能不必要;只有确认它没有承担背景、padding、布局参数或事件处理等职责后,才能去掉它,让 RelativeLayout 成为根 View。

Lint

原文列出的未使用变量、空指针、空分支、多余的 return / continue 和循环简化,也可能来自 IDE 的代码检查,并不都是 Android Lint 的性能规则。把 for 改成增强 for,或者少一个容器,都不能单凭代码形式保证更快。减少层级主要影响 inflate、measure 和 layout;只有消除了实际重复绘制,才会相应减少像素过度绘制。

Tracer for OpenGL ES(历史工具)

下面是当年的流程,不能照搬到 Android Studio 3.2 及以后的版本。原来可以在 Android Device Monitor 中打开 Tracer for OpenGL ES,通过 Open Perspective 找到面板,再新建 GLTrace,选择应用和 Activity,点击 Trace 开始、Stop 停止。

Tracer

我当时通过逐帧回放,检查默认背景和 CustomViewBehind 背景是否还在绘制。下面留下了优化后的截图,但这里没有原始 GLTrace 文件可供重新分析。

Tracer

如果多个交互帧中都不再绘制这些被完全遮挡的背景,确实减少了相应的绘制工作。但减少多少 GPU 时间、是否改善掉帧,需要另做前后测量。本文的历史截图没有提供这部分数据。


参考资料

  1. Android 官方:减少过度绘制
  2. Android Device Monitor 的弃用与替代工具
  3. Layout Inspector
  4. Window.setBackgroundDrawable()
  5. Drawable.setBounds()
  6. 优化 View 布局
  7. Perfetto FrameTimeline
  8. 原文参考:Android Performance Case Study(历史链接,本次未能重新访问,不作为新增结论的依据)。

作者:Gracker

出处:androidperformance.com

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

打赏一下: 微博打赏

关于我 && 博客

下面是个人的介绍和相关的链接,期望与同行的各位多多交流,三人行,则必有我师!

  1. 博主个人介绍 :里面有个人的微信和微信群链接。
  2. 本博客内容导航 :个人博客内容的一个导航。
  3. 个人整理和搜集的优秀博客文章 - Android 性能优化必知必会 :欢迎大家自荐和推荐 (微信私聊即可)
  4. Android性能优化知识星球:付费社群已于 2026 年停止运营,不再招收新成员;此处保留历史介绍。

一个人可以走的更快 , 一群人可以走的更远

微信扫一扫

CATALOG
  1. 1. 前言
  2. 2. 定位过度绘制区域
    1. 2.1. 打开 GPU 过度绘制选项
    2. 2.2. 打开待测页面
    3. 2.3. 从文件管理器的图分析可疑区域
  3. 3. 优化过度绘制区域
    1. 3.1. 去除被完全遮挡的背景
    2. 3.2. 消除子控件的多余背景
    3. 3.3. 进一步检查列表项
  4. 4. 优化代码
    1. 4.1. Lint 工具
    2. 4.2. Tracer for OpenGL ES(历史工具)
  5. 5. 参考资料
  • 关于我 && 博客