简化复杂的视图层级
App的核心是使用视图层级来创造用户界面和视觉体验。随着app的功能越来越丰富,视图层级会越来越复杂,并且成为性能问题的来源之一。最常见的表象是app卡顿,尤其是渲染复杂视图时。
简化或者重新布局你的视图层级可以提升app的性能表现,尤其是在低配设备和早期的Android版本上。额外的好处是,你的app会变得更容易维护。
前期准备阅读通过移除无用的背景减少过度绘制这篇文章,来排除导致卡顿的这一常见原因,避免和视图层级带来的问题混淆在一起。
分析视图层级
分析视图层级就是使用几个工具来定位并修复性能问题。所以,有时你只需要一个工具,有时则需要全部的工具一起使用来优化性能。
GPU呈现模式分析
- 运行GPU呈现模式分析并且观察柱状图蓝色的部分。 如果蓝色的部分过高并且导致柱状图高度超过了16ms的标志线,那就是你的app花费了大量时间来更新display list。在Android 6.0版本中增加了额外的颜色,表示Measure/Layout的浅绿色也容易超乎预期的耗时。导致这些的一个原因就是试图层级过于复杂了。当然这只能告诉你有问题,而不能告诉你问题出在哪里。让我们接着往下看。
显示GPU视图更新
- 在你的设备上运行显示GPU视图更新工具。在开发者选项中,找到硬件加速渲染然后打开显示GPU视图更新。
- 操作你的app。
- 在屏幕上的试图更新时会闪烁红色。如果你注意到屏幕上和正在更新的区域无关的视图闪烁,那很可能是两者之间在视图层级上相关联所以导致了视图被不正确的失效了。这样,你就可以关注在这些区域上来更快的查找到问题。
Hierarchy Viewer
这就是你要做大量工作的工具了
- 开启 Hierarchy Viewer工具。
- 找到你app中仍然有大量过度绘制的视图层级。考虑重新调整你的视图来减少过度绘制。
- 定位到视图层级复杂的区域,考虑如何能简化它。
- 分析视图层级中额外潜在的问题节点。
使用lint深入挖掘问题
在布局文件上使用lint来搜寻对视图层级可能的优化。然而关于lint的好处需要另写一篇文章。
简化视图层级
移除对最终图像无用的视图
按照如下步骤来确定对最终呈现到屏幕上的图像无用的视图:
- 在Hierarchy Viewer中,从叶子节点像根节点查看视图层级。
- 点击每一个节点来查看屏幕当前的图像。在Layout View窗口查看视图是如何分层的
- 如果一个之前可见的视图被完全隐藏,那么你可能根本就不需要这个视图,如图1.
- 在你的代码中移除被完全遮盖,从来不显示或者在屏幕区域外的视图。
图1. 视图2和3被完全遮盖可以安全的移除。
扁平化视图层级来减少嵌套
- 你的视图层级中有没有看起来类似图2的嵌套?
- 当可行时,使用相对布局替代嵌套的线性布局来扁平化视图层级。查看优化视图层级这篇文章.
图2. 这个层次很深的视图层级可以变得扁平化来提升性能。
减少视图的数量
- 如果你的用户界面有很多简单的视图,你可以在不影响用户体验的前提下,像图3那样结合其中的一些。
- 所有的改变都会影响你呈现信息的方式当然设计上要做出权衡。不过要记住性能表现是你app成功与否最重要的一点,无论什么情况下,你都应该尽可能的选择优化它。
- 合并一些视图。比如:如果你减少字体和样式,就可以合并text view。
- 重新设计你的用户界面来使用更少的视图。
图3. 合并视图的列子
简化会导致多次layout的嵌套布局
像RelativeLayout这样的父视图,需要两次布局来最终确定子视图的位置。结果就是,他们的子视图也需要两次布局。当你再把这些父视图嵌套在一起时,每一个视图层级的布局的次数就会以指数级增长。
举个列子,RelativeLayout中嵌套一个ListView,ListView中嵌套一个GridView,GridView中嵌套一个view,这会导致8倍的布局次数,如图4.
使用任何以上的容器作为一个复杂视图的根节点,比如一个很深的子树的父节点,或者在布局中大量使用,都会影响性能。所以,多考虑如何在避免布局次数指数级增长的情况下达到相同的布局效果。比如,使用不设置gravity的gridview来替代relative layout作为根节点。