对于Android中的布局优化,主要分为四点。
1.减少控件树的层级
2.include标签的使用
3.merge标签的使用
4.ViewStub视图的使用
看上去有四点,其实总的来说就只有第一点,减少控件树的层级,之后的三点其实就是通过不同的方式来减少控件树的层级,本文重点介绍后两种方式,merge标签的使用,以及ViewStub视图的使用。
我们知道,Android中的布局是通过xml文件实现的,那么xml文件又是如何和activity进行关联的呢?很简单,setContentView嘛,那么setContentView具体执行了什么操作呢,相信大家对这个方法不会感到陌生。
View.inflate(this,R.layout.activity_main,null);
其实setContentView就是将我们的xml文件进行解析,然后根据View的标签和属性实例化对象,加载到对应的父控件中,由此可见,只要减少控件树的层级就等于是减少了实例化对象的数量,也就增加了页面渲染的效率。
在介绍merge和ViewStub之前,我先介绍AndroidStudio下的控件树预览工具——HierarchyViewer
在AndroidStudio下点击如下按钮调出设备管理器
再点击调出HierarchyViewer
那么HierarchyViewer就被启动了,下面就是关于merge和ViewStub的介绍啦
一.merge
新建一个xml布局,代码如下。
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.administrator.mergeandviewstub.MainActivity"
android:background="#ffffff"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/textView"
android:layout_gravity="left|top" />
</FrameLayout>
很简单的布局,就是一个FrameLayout嵌套一个TextView,现在我们运行一下,看HierarchyViewer所呈现出来的层级图
由上图中的层级关系我们可以看到,在我们的xml文件外还有一个rootView,类型和我们xml中的根视图是一样的,都为FrameLayout,这就满足了我们使用merge标签的
两个重要条件。
1. <merge />只能作为XML布局的根标签使用!
2.xml布局的根视图与contentView的视图类型相同(都为FrameLayout)!
我们来看更改FrameLayout标签后的布局文件
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.administrator.mergeandviewstub.MainActivity"
android:background="#ffffff"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/textView"
android:layout_gravity="left|top" />
</merge>
再来看HierarchyViewer中的控件树结构
很明显少了一层FrameLayout,而将TextView直接加到了ContentView的FrameLayout上了。
2.ViewStub
我们在实际的开发中总会遇到这样的情况,在某些情景下,我们需要显示指定的View,在有些情景下,我们又需要隐藏指定的View,假设我们一开始我们将该View隐
藏,这个控件是否会在界面渲染的时候添加到控件树上呢?我们先来试试看。
xml代码
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Text"
android:visibility="gone"
android:id="@+id/textView"
android:layout_gravity="left|top" />
</merge>
如上,我已经TextView的visibility设置为Gone,我们再来看控件树的结构:
如图所示,我们看到TextView依旧被渲染了,可见即使在该View不可见的情况下,在解析xml的标签集合时还是解析到了这个TextView。
下面我们换一种方式,使用ViewStub来控制View的可见与否。
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
>
<ViewStub
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/index"
/>
</merge>
index.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
/>
</RelativeLayout>
现在直接执行,查看控件树的渲染情况。
由上图可见,渲染出来的只有一个ViewStub,ViewStub所包含的视图并没有被渲染出来,现在我们让ViewStub的视图变为可见。
public class MainActivity extends AppCompatActivity {
private ViewStub viewStub;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewStub = (ViewStub)findViewById(R.id.viewstub);
viewStub.inflate();
//viewStub.setVisibility(View.VISIBLE);
}
}
执行viewStub.inflate()和viewStub.setVisibility(View.VISIBLE)都可以达到效果。
控件树。
由此可见,ViewStub被包含着TextView的RelativeLayout所替代了,隐藏的View被展示。
综上所述,不管是include,还是merge,亦或者是ViewStub,都是通过减少控件树的层级来达到布局优化的目的。