布局文件的复杂程度涉及到程序界面的渲染速度,要优化APP性能,先从最基本、最直接的布局文件开始。
一、优化布局层次
非必要情况下,尽量降低布局的嵌套层次,将布局最大扁平化。如针对下图1的UI,应该选择图2中的实现,而非图3的:
图1:左侧为一个ImageView,右侧为两个垂直分布的TextView
图2
图3
很明显,图3的实现比图2的多了一层LinearLayout,这样一来,当系统在渲染两个子控件TextView时,就会先去处理其父控件LinearLayout,摸清了父控件的位置、大小情况,才好准确的安排其子控件,因此,图3比图2多走了一步。如果这只是一个单独界面还好,只渲染一次还可以,万一将这个UI作为Listview或Recyclerview的Itemview呢?那白白浪费的资源就会成倍增长啦。
另外一点,如果用到几个LinearLayout嵌套时,谨慎使用layout_weight属性,因为该属性会使得这类LinearLayout被测量两次。
顺便提一点,如果现在你想查看某个布局文件的层次,SDK里的Hierarchy Viewer 工具已经过时了,如果你的AS版本为3.1以上,那你可以用AS里面的Layout Inspector代替:首先将设备通过USB连接上电脑后,在设备上运行你的APP,依次点击AS上的Tools-Android-Layout Inspector,选择你的进程和对应的界面即可显示所选界面的布局层次了。
以下是几点布局技巧:
1.如果有使用了一个LinearLayout包裹一个Imageview和Textview,那最好换成一个复合控件,例如通过Textview的drawableLeft等属性实现图片的显示;
2.如果根布局是FrameLayout并且不带background和padding属性的话,则建议将FrameLayout换成merge标签;
3.布局文件中尽量不要保留那些既没有background又没有子控件的布局;
4.如果一个父布局仅有一个子控件,并且这个父布局不是ScrollView,也不是根布局,也没有background,那么可以将其子控件移到外部来,再将这个父布局移除;
5.android布局默认的最大的嵌套层次是10层,所以能不嵌套则不要嵌套,尽量使用RelativeLayout或GridLayout等布局避免嵌套提升性能。
二、通过include标签重复使用布局
如果你有某些诸如取消/确定按钮或自定义的progressBar等UI是可共用的,那么你只需要在使用的布局中通过include标签将目标布局嵌入引用进来即可,不需要重新写一遍。
但这会引发一个布局层次嵌套的问题:即如果当前inlude的地方其父布局是一个垂直的LinearLayout,而引用的目标布局其根布局也是一个垂直的LinearLayout的话,那么就白白多了一层嵌套。为了优化这个问题,我们需要将这个可共用的布局根布局替换为merge标签,这样一来,系统在渲染这个界面的时候会自动忽略merge标签,共用的布局中子控件直接受外部的LinearLayout约束。
如果我们在当前布局中include引用了一个共用布局后,需要对这个共用布局个性化以满足当前布局的需求,必须同时为include标签添加layout_width属性和layout_height属性,否则重写的其他属性都不会起作用。
三、viewStub延迟加载布局
viewStub作用与include类似,都可以将一个已存在的布局引用到当前布局来显示,只是进入当前布局的界面时,include进来的布局就会渲染,而viewStub进来的话则不会随当前布局渲染,只有你想让它显示的时候才会开始渲染。这就做到了即用即加载,会在一定程度上提升进入界面的用户体验。以下为部分示例代码:
其中的include_test即需要懒加载的引用布局文件:
<ViewStub
android:id="@+id/stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout="@layout/include_test"
/>
控制引用的布局文件的显示隐藏:
((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
注意:如果需要懒加载的布局根标签是merge,则用viewStub引用的话则会崩溃。