性能优化之过度绘制篇

最近接到一个任务,优化项目中的过度绘制问题。提到过度绘制,脑海中会浮现出includemergeViewStub标签,减少ViewTree的层次等等优化布局相关,但具体怎么进行优化,有一种无从下手的感觉。认真仔细阅读了官方文档中关于绘制过度的讲解,豁然开朗。
网上关于过度绘制的博客也不少,但自己喜欢对自己做的功能进行总结记录,所以抽时间写下本篇博客,对过度绘制进行总结,方便日后查阅。

分析工具

一.使用调试GPU overdraw工具从视觉分析:
手机:设置->辅助功能->开发者选项->调试GPU过度绘制->显示过度绘制区域
这里写图片描述
二.使用布局检查器从ViewTree结构分析:
使用Hierarchy Viewer进行ViewTree结构分析,但打开SDK->tools发现SDK中去掉了hierarchyviewer.bat,新增了Layout Inspector进行替代。
使用方法:Android Studio点击 Tools > Android > Layout Inspector
使用Layout Inspector选择对应进程,对相应界面就行布局检查,会保存为.li文件并打开,借用官网的图进行说明:
共分为三部分:
View Tree:视图在布局中的层次结构。
Screenshot:带每个视图可视边界的设备屏幕截图。
Properties Table:选定视图的布局属性。
这里写图片描述

优化

优化过度绘制是Android性能优化的重要部分,可从以下几方面进行优化:
一.去除无用背景:
当布局中有多重背景时会导致视图的过度绘制,通过删除删除布局中不需要的背景来减少视图的过度绘制。
在布局中,如果存在多个线性布局重叠时,可以考虑只针对最上层的布局设置背景色,而不需要每一个布局(例如LinearLayout)都设置背景色,过多的相同的背景色会导致过度绘制。
二.优化视图层次结构,减少视图层级:
优化视图结构,减少布局层级,可以有效的较少过度绘制,可使用Lint检查结果进行参考帮助优化性能。
Lint使用:Android Studio的Analyze> Inspect Code使用Lint工具,查看结果中的performance根据提示进行优化。
1.去除不需要的布局层级:
可根据上述分析工具Layout Inspector直观地分析视图层次结构,减少不需要的视图层级的绘制。
当然Lint检测结果中也会有提示,Useless parent layout
比如:
Lint中的提示
(1)This ‘RelativeLayout’ layout or its ‘RelativeLayout’ parent is useless; transfer the ‘background’ attribute to the other view。
但只会检测出最外层布局且检查不全面,具体需要根据Layout Inspector分析布局层次,一层布局通过添加背景,marginLeft等属性就可实现的效果没必要多层嵌套。
(2)Layout hierarchy is too deep
(3)Layout has too many views
对应布局中有太深层级和太多view的警告,有时功能界面确实复杂,但我们赢尽可能地减少view的使用和布局层次,必要时使用include,merge,viewStub进行优化。
2.TextView尽量使用CompoundDrawable::
布局中图标和文字的结合,这样的效果太普通不过了,可能会习惯使用LinearLayout/ReleativeLayout下嵌套ImageView和TextView来实现布局效果。
在LinearLayout布局中,如果存在相邻的ImageView和TextView,可以使用compound drawable合二为一成为一个TextView,ImageView中的图片变成TextVIew的drawableTop/drawableLeft/drawableRight/ddrawableBottom属性,之间的间隔使用drawablePadding属性来代替。
比如:
Lint中的提示:
Node can be replaced by a TextView with compound drawables
但有些效果使用textview的drawable属性并不能实现相同的效果,此时还是需要使用多个view来实现的。
3.优化嵌套layout weights:
Lint 中的提示:
Nested layout weights
嵌套layout weights时权值会被计算两次, 改变时, 会按照比例进行改变,影响性能。此时应使用RelativeLayout或GridLayout代替LinearLayout减少没必要的layout weights嵌套。
4.使用include,merge,viewStub标签:
(1).include标签共享布局:
将通用的布局抽取出来,独立成一个XML文件,在需要用到的页面中使用include标签引入进来,减少代码量,便于修改。
(2).ViewStub标签实现延迟加载:
ViewStub是一种不可视并且大小为0的视图,可以延迟到运行时才填充布局资源。当ViewStub设置为可见或者被inflate之后,会填充布局资源,ViewStub会被填充的视图代替,和普通的视图没有区别。
ViewStub在需要显示的时候才会进行视图的填充,实现延迟加载的目的。
(3).merge标签减少布局层次:
当一个独立的布局文件最外层是FrameLayout且这个布局不需要设置背景等属性时或者当前布局是另外一个布局的子布局时,可以使用merge来减少布局的层次。
5.在自定义view的onDraw()中过度绘制问题。
在自定义view的onDraw中,如果涉及到重叠的绘制view时,可以考虑利用局部绘制避免过度绘制。
考虑到效率和性能问题,界面是有一定刷新频率的,每一次刷新都会调用View的onDraw方法,而View提前绘制就是在onDraw中进行,避免在onDraw创建对象,避免在onDraw进行绘制,应在构造函数中画好,交给onDraw。

总结

在网上查的资料都是理论篇,具体的需要在实践中理解Android的绘制原理,优化过度绘制,从而给用户更流畅的画面和更好的体验。
参考文章
https://developer.android.com/topic/performance/rendering/overdraw
https://blog.csdn.net/qq_19711823/article/details/65627790