最近看到这篇文章 [Android 性能优化系列]布局篇之减少你的界面层级,里面介绍了HierarchyViewer(层级检视器),于是按部就班,在 sdk>tools 下面找到 hierarchyviewer.bat 双击运行,但却出现如下提示:
The standalone version of hieararchyviewer is deprecated.Please use Android Device Monitor (tools/monitor.bat) instead.
即单独版本的 hieararchyviewer 已经被弃用了。请使用 Android Device Monitor(Tools|Android| Android Device Monitor) 代替。
打开后按如下方法切换到HierarchyViewer
左边的窗口有一个Windows标签,下方列出了与PC相连的android设备和设备上所有运行的进程。活跃的进程是粗体展示的。第二个标签给出了一个选定的已渲染布局的详情(后面细说)。中间的部分是可缩放的app视图结构树形图。点击某一个view能看到在设备上展示的样子和一些额外的数据。右边有两个视图窗口:树形结构总览和布局视图。树形结构总览显示了整个view的层级,里面有一个盒状方框,显示缩放的中心部分在整个树形结构当中所处的位置。布局视图窗口以高亮深红色的区域表示视图中被选中的部分(浅红色展示的是父布局视图)。
在这个中间的特写视图重口里面,你可以点击一个单独的view来查看该view在android设备屏幕上展示的位置。点击树形图工具栏里红绿紫三色的维恩图图标,弹出的视图口还能显示子视图的数量以及视图测量,布局,绘制所花费的时间。这个时间是被选择的view及其所有子节点所花费时间的总和。(图4-3中,我选择了最顶部的view来获取整个view结构的时间)
消息列表列出了最顶部列表总共包含181个视图,测量的总时间为3.6ms,布局花费7ms,绘制花了14.5ms(总共大约25ms)。要缩短渲染这些视图的总时间,我们有必要看一下app的树形结构图预览,看看所有的视图是怎么拼凑到一起的。从树形结构图上可以看出屏幕里有非常多的view,渲染树的结构相对扁平。扁平的渲染树是性能优良,因为XML视图的”深度”可能会对渲染时间产生不利影响。即使在扁平的XML中,仍需要26ms绘制时间,说明扁平的结构也有可能会卡顿,也需要去考虑怎么优化。

排查一个新闻类app的树形结构(如图4-4),大致可以看三个区域:头部(底部蓝色的方框),文章列表(两个橙色的方框表示两个不同的标签),单篇文章的视图是用红色方框来标注的。内部标题视图的结构重复出现了九次,5个在上面橙色的方框内,4个在下面的方框内。最后,我们可以看到从边上拉出来的导航栏是用底部绿色的方框标出来的。头部用了22个view,两个文章列表个用了67和44个view(每个标题部分使用了13个view),导航抽屉使用了20个。这样我们还剩下18个view没有计算在内。剩下的这些view其实是在滑动手势动画过程当中生成的。很显然,view的数量很多,要做到不卡顿需要让view的绘制非常高效才行。

仔细看下头条,列表中显示一个标题是由13个view组成的。每个标题的结构有5层之深,一共花费0.456ms来测量,0.077ms来布局,2.737ms来绘制。第五层是通过第四层的两个相对布局来填充的(蓝色高亮显示),而这些又是通过第三层的另一个相对布局来连接的(绿色高亮)。如果我们把第四第五层的view都移到第三层来,我们可以少渲染一整层。而且我之前在Remeasuring Views 中解释过,每一个相对布局都会被测量两次,套嵌的相对布局会迅速导致测量时间的增加。
现在,你可能已经注意到了每个view里红色,黄色和绿色的圆圈。它们(从左到右)表示该view在那一层树形结构里测量,布局和绘制所花费的相对时间。绿色表示最快的前50%,黄色表示最慢的前50%,红色表示那一层里面最慢的view。显然,红色的部分是我们最需优化的对象。
再看下文章标题的树形结构,绘制最慢的view是右上角的ImageView。顺着ImageView一直找到文章parent view,parent view是通过两个相对布局来填充的(这里增加了测量的时间),然后是3个没有子节点的view(在最底部)。这3个view可以优化合并成一个view,这样能减少两个layer的渲染。
我们再看另一个新闻类app是怎么来减少标题view里面的子view数量的。从图4-6里能看到一个和图4-5类似的树形结构图。
实际上,图4-6里的标题view也有相对布局(蓝色的部分)的问题,这导致一共消耗了1.275ms的测量时间,0.066ms的布局时间, 3.24ms的绘制时间(总共是4.6ms)。看到这些的时候,开发人员会回到绘图板,并且建立一个更漂亮的 UI——带有更大的图像和共享按钮 — — 但是一个扁平的层次结构。(如图4-7所示)。
再看下标题视图的渲染时间(三层的结构),只用了4.2ms,比之前节省了400ms,而且还展示了更大的UI!
为了更好的了解这部分的优化,我们再看另一个简单的app——”Is it a goat?”。这个简单的app在山羊图片旁边展示了几张带有检查标志的图片。界面使用了几种不同的布局方式,有未经优化缓慢的布局方式,也有优化后快速的 XML 布局。仔细的查看这些布局,然后一步步优化它们,我们就能清楚的理解怎么去优化一个app的渲染性能了。我们分几步来进行优化,每一步改变都可以通过Hierarchy View可视化的查看。每换一种布局方式,xml渲染的性能要么变好,要么变差。我们先从性能差的布局方式开始。先快速的扫一眼图4-8里的Hierarchy View。
未经优化的“Is it a Goat?” app的Hierarchy view
这个简单的app里有59个view。但是和图4-4里的app不同,这个app的树形结构更扁平,水平方向的view更多一些。叠加的view越多,渲染就会越费时,减少view树形结构的深度,app每一帧的渲染就会变快。
蓝色方框里面的view是action bar。橘色方框里的是屏幕顶部的text box,紫色方框里展示的是山羊的详细信息(有6个这种view)。红色方框标示了7个view,每个都增加了树形结构的深度。我们仔细看些这7个view其中三个的re测量数据(图4-9)。
当设备开始测量 views的时候,先从右边的子views开始,然后到左边的父views。右边ListView包含6行数据,一共37个view,花了0.012ms来测量。把这个ListView加到中间的Linear布局之后,变成38个views。有意思的是,测量的时间由于re测量被触发,瞬间跳到了18.109ms,是原来的三个数量级。Linear布局左边的相对布局使得测量的时间再次翻倍到33.739ms。再依次往左继续观察(图4-8里红色方框部分),测量的时间叠加到了68ms。但是只要移除上面的一个Linear布局,测量的时间瞬间降到了1ms。我们可以移除更多的层让树形结构更扁平一些,这样我们可以得到图4-10里的结果,层数减少到了3层。
我们可以继续看下山羊信息到row展示部分,来继续减少view结构的深度。每一行山羊信息有6个view,一个有6行数据在屏幕中展示(图4-8中有一行数据是用紫色方框高亮的)。我们用Hierarchy View看下一行view的结构是怎么样的(图4-11),先看下左边两个view(一个Linear布局,一个相对布局),这两个view唯一的作用就是加深了树机构的深度。Linear布局连接了相对布局,但并没有展示其他什么内容。
因为相对布局会测量两次(我们现在关注优化测量的时间),我们先移除相对布局(图4-12)。这样树形结构的深度从4减到了3,渲染立马快了一些。
然而,效果还并不理想。我们继续移除Linear布局,同时调整下相对布局来展示整个row的信息(如图4-13所示),这样深度近一步减少到了2。渲染又快了0.1ms。这样看来优化的途径有很多种,多尝试总是有好处的。
Hierarchy Viewer(不止是树形结构图)
Hierarchy Viewer还有许多额外的灵巧的功能,可以帮助开发者更好的理解overdraw(重复绘制)。从左到右看树形视图上方任务栏的选项,通过这些选项,你可以实现很多有用的功能,比如:
1.把view的树形结构图保存为png格式(图标是一个程式化的磁盘)。
2.导出为photoshop的格式(描述为“Overdrawing the Screen”)。
3.重新加载一个view(第二个紫色树形按钮)。
4.在另一个窗口里打开较大的view结构图(地球状的图标),通过新开窗口中改变背景色的选项,我们可以很容易看是否有重复绘制。
5.使当前的view失效(禁止符号)。
6.让view进行布局。
7.让view输出draw命令到Logcat(没错,紫色树形图标的第三个功能)。这是一个用来查看每一步到底触发了哪些OpenGL行为的很好的方法。这个功能对openGL的专家做深度优化比较有用。
Hierarchy Viewer对于优化app的视图树形结构重要性不言而喻了,很可能会帮你节省几十毫秒的渲染时间。
View的重用
如果一个程序员面向对象编程经验丰富,他就会尽可能重用创建的view(而不是每次都创建)。拿上面山羊app作为例子,其实每一行展示的layout都是重用的。如果xml文件里最外层的view只是用来承载子view的,那这个view只不过是增加了view结构的深度,这种情况下,我们可以移除这个view,用一个merge标签来代替。这种方式可以移除树形结构里多余的层。
大家可以从github上下载这个山羊app练习下,改变里面xml文件的布局方式,再用Hierarchy View工具看下渲染时间的变化。
参考:Android UI性能优化详解
原文:Chapter 4. Screen and UI Performance
译文若有不妥之处,望您斧正
此文仅供本人学习使用,不保证完全准确