子曰:温故而知新,可以为师矣。 《论语》-- 孔子
作为性能优化专栏的第三篇,我们就来说一说 UI 绘制优化的思路以及一些解决方案。
1. CPU 与 GPU
CPU
:
- 中央处理器。CPU 的任务繁多,做逻辑计算外,还要做内存管理、显示操作,因此 在实际运算的时候性能会大打折扣,在没有 GPU 的时代,不能显示复杂的图形,其运算速度远跟不上今天复杂三维游戏的要求。即使 CPU 的工作频率超过 2GHz 或更高,对它绘制图形提高也不大。这时 GPU 的设计就出来了。
GPU
:
- 为了提高图形显示效率以及复杂的图形,设计出了 GPU。主要是为了帮助 CPU 分担图形显示。下面显示一张 GPU 的图:
-
黄色的 Control 为控制器,用于协调控制整个 CPU 的运行,包括取出指令、控制其他模块的运行等。
-
绿色的 ALU ( Arithmetic Logic Unit )是算术逻辑单元,用于进行数学、逻辑运算。
-
橙色的 Cache 和 DRAM 分别为缓存和 RAM ,用于存储信息。
从结构图可以看出, CPU 的控制器较为复杂,而 ALU 数量较少。因此 CPU 擅长各种复杂的逻辑运算,但不擅长数学尤其是浮点运算。 我们页面是一个个像素点,以16进制展示,假如某个背景要从白色到红色,明显就是进制之间的转化,那么 ALU 显然擅长这个,所以在 GPU 中 ALU 数量较多的原因。
2. xml 显示过程
Android 开发的 xml
布局是如何显示到页面上? 下面这一张图说明了整个流程:
好了,现在大家应该对 UI 布局渲染流程与绘制有了一个基本的了解。那么我们需要优化什么?想要优化,肯定是有了问题,才会想着优化,那么 UI 的渲染可能会导致什么问题? 那就是过度渲染会导致页面卡顿,这个想必大家应该都遇到过。
3. 60Hz 刷新频率
提到过度渲染,那么就不得不提 60Hz 刷新频率由来:
12 fps
:由于人类眼睛的特殊生理结构,如果所看画面之帧率高于每秒约 10-12 帧的时候,就会认为是连贯的。24 fps
:有声电影的拍摄及播放帧率均为每秒 24 帧,对一般人而言已算可接受。30 fps
:早期的高动态电子游戏,帧率少于每秒 30 帧的话就会显得不连贯,这是因为没有动态模 糊使流畅度降低。60 fps
:在与手机交互过程中,如触摸和反馈 60 帧以下人是能感觉出来的。 60 帧以上不能察觉变化,当帧率低于 60 fps 时感觉的画面的卡顿和迟滞现象。
Android 系统每隔 16ms 发出 VSYNC 信号 (1000ms/60=16.66ms) ,触发对 UI 进行渲染, 如果每次渲染都成 功这样就能够达到流畅的画面所需要的 60 fps ,为了能够实现 60 fps ,这意味着计算渲染的大多数操作都必须 在 16ms 内完成。
16
毫秒的时间主要被两件事情所占用:
- 第一件:将 UI 对象转换为一系列多边形和纹理。
- 第二件: CPU 传递处理数据到 GPU 。
所以很明显,我们要缩短这两部分的时间,也就是说需要尽量减少对象转换的次数,以及上传数据的次数。
这边提供两个过度绘制的情况:
- 自定义控件中 onDraw() 方法做了过多重复绘制。
- xml 布局层次太深,重叠性太强。用户看不到的区域 GPU 也会渲染,导致耗时增加。
4. 查看页面是否过度绘制
那么对于我们自己的项目,如何去查看页面是否过度绘制呢?
- 手机开发者选项 --> 打卡调试 GPU 过度绘制。
- 其中颜色代表渲染的图层情况,分别代表 1 层,2 层,3 层,4 层。如下图:
好了,现在大家可以打开自己的项目,看一看自己项目中的页面,如果页面中红色区域较多,那么明显是需要优化的,尽量都是绿色显示,有些可能业务需要,没办法优化,那就不能强求了。
5. UI 绘制优化方案
每个人的项目都有所不同,需求也不一样,这边就不具体展示 xml 页面如果优化了,我总结了一下我自己优化的几个方案,大家都可以去尝试一下:
1. 减少背景重复
:
在自己的项目中对某些布局优化时,可以反问自己,这布局中的背景是否需要,是否可以删除多余的布局,能否用 RelateLayout 减少层级嵌套,实现同样的效果。
- 主题中的设置:去掉所有 Activity 主题设置中的属性,直接在
styles.xml
文件中设置<item name="android:windowBackground">@null</item>
。 - 非业务需要,不要去设置背景。意思是在 xml 文件中,有些整体区域的背景能不设置就不要设置,可以放在子控件中设置,就在子控件中设置。
2. 自定义控件中,对于重叠显示的图片,可以用裁剪的方式,减少重叠部分
。
3. 能在一个平面显示的内容,尽量只用一个容器;能复用的代码,用include处理,可以减少GPU重复工作
:
- 这边比较推荐的是使用
include
和merge
这两种方式。至于具体做法,网上搜索,写的好的文章很多,这边推荐一篇比较不错的文章:Android 布局优化之include与merge,写的很详细了。
4. 使用ViewStub进行布局的懒加载
。
写在文末
纸上得来终觉浅,绝知此事要躬行。 《冬夜读书示子聿》-- 陆游
好了,关于 UI 绘制优化的思路以及解决方案
就说完了,各位小伙伴可以在项目中借鉴文章中给出的思路优化。