<span style="font-size:18px;">原文地址:http://periplanisi.com/android/2013/11/multi-pass-viewgroup-and-performance/</span>
回溯到2009年,罗马一个家伙写了一篇很有意思的文章,解释了使用RelativeLayout相比于使用LinearLayout的一些好处。不幸的是,很多人读了那篇文章之后,都信奉用RelativeLayout是更好的选择。然而,这却是一个完全错误的结论。
然而这篇文章是非常好的,它提供了一些方法去减少布局的深度,和UI组件的使用数量。当然,第一条原则就是尽可能的去让你的布局扁平化,减少不必要的viewGroup组件,使用merge标签等。
然而文章说的那些方案,并不能保证RelativeLayout会比LinearLayout表现出更好的性能。事实上你去检查RelativeLayout的实现,你会发现,RelativeLayout会调用子View的onMeasure方法两次!这必然会降低性能。如果RelativeLayout没有很深的子View层次,这种性能的影响可能还没那么严重,但是RelativeLayout如果作为一个布局的根View,并且包含很多的子View,那么这种性能影响可能很大。所以最好避免使用RelativeLayout作为布局的根View。
当LinearLayout使用Weight属性的时候,为了去准确测量出所有子view 的尺寸,同样存在上面的问题(会调用子View的onMeasure两次)。所以使用LinearLayout的时候要注意Weight属性的使用。
另外在View使用中还有一件需要注意的事情就是,listView的使用性能。listview使用wrap_content属性同样会降低性能,因为listview存在很多行元素,测量会比较耗时。所以说除非是不得已,否则一定要用match_parent。
下面我们会给一些简单的例子来说明这些问题。
假设我们的Activity加载这样一个布局,根View是用RelativeLayout,里面有一个子View是ListView,ListView的布局属性是wrap_content。
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="@+id/mylist"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
然后我们提供一个BaseAdapter,加载下面的布局作为ListView每行的布局。注意到这里的布局的根View也是RelativeLayout。
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/some_text"
/>
</RelativeLayout>
运行上面的试验,ListView在屏幕上面创建了20行数据,但是我们发现onMeasure一共被调用了320次!
通过上面的分析,我们知道这里有三个点可以去做优化。
1、把Activity布局的RelativeLayout改成LinearLayout
2、把ListView的属性从wrap_content改为match_parent
3、把ListView每行布局的RelativeLayout改为LinearLayout
果不其然,我们发现优化之后,onMeasure的调用降低到了40次(降低8倍),同时Activity的加载时间降低了100ms(这个依赖设备)。当然,如果我们对一个更加复杂的View去做优化会有更好的效果。
在4.4的系统中,做了一些缓存策略去优化这种过度的onMeasure调用。