Android布局优化:include 、merge、ViewStub的详细总结

版权声明:本文出自汪磊的博客,未经做者容许禁止转载。

本篇博客主要是对上篇博客的补充Android性能优化之UI渲染性能优化, 没有什么新东西,以为应该是都掌握的玩意,写出来也只是本身作个小小的总结。 html

1、include的用法以及注意点android

在开发Android布局时,咱们常将一些通用的视图提取到一个单独的layout文件中,而后使用<include>标签在须要使用的其余layout布局文件中加载进来,好比咱们本身App导航栏等。这样,便于对相同视图内容进行统一的控制管理,提升布局重用性。性能优化

下面咱们以大部分项目中都有的头部导航栏为例,说明一下include的使用,好比咱们项目本身统一头部导航栏,抽取布局以下:微信

titlebar.xml:工具

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent" >
 5     
 6      <Button  7         android:id="@+id/back"  
 8         android:layout_width="wrap_content"  
 9         android:layout_height="wrap_content"  
10         android:layout_alignParentLeft="true"  
11         android:layout_centerVertical="true"  
12         android:text="返回按钮" />  
13   
14     <TextView 15         android:id="@+id/title"  
16         android:layout_width="wrap_content"  
17         android:layout_height="wrap_content"  
18         android:layout_centerInParent="true"  
19         android:text="提示文字"  
20         android:textSize="20sp" />  
21   
22     <Button 23         android:id="@+id/close"  
24         android:layout_width="wrap_content"  
25         android:layout_height="wrap_content"  
26         android:layout_alignParentRight="true"  
27         android:layout_centerVertical="true"  
28         android:text="关闭按钮" />  
29 
30 </RelativeLayout>

很简单,就是左右各一个按钮,中间是一个提示文字。使用也比较简单,以下:布局

activity_main.xml:性能

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     tools:context="${relativePackage}.${activityClass}" >
 6 
 7     <include  8         android:layout_width="match_parent"
 9         android:layout_height="40dp"
10         layout="@layout/titlebar" />
11 
12     <Button 13         android:layout_width="wrap_content"
14         android:layout_height="wrap_content"
15         android:layout_centerHorizontal="true"
16         android:layout_centerVertical="true"
17         android:onClick="click"
18         android:text="点我。。。" />
19 
20 </RelativeLayout>
include标签使用仍是很简单的,主要经过layout属性声明要引入的布局便可。运行程序界面以下:

include标签使用注意点:
1,<include>标签当中,能够重写全部layout属性的,如上面include中指定的layout属性将会覆盖掉titlebar中指定的layout属性。
而非layout属性则没法在<include>标签当中进行覆写。另外须要注意的是,若是咱们想要在<include>标签当中覆写layout属性,
必需要将layout_width和layout_height这两个属性也进行覆写,不然覆写效果将不会生效
2,一个xml布局文件有多个include标签须要设置ID,才能找到相应子View的控件,不然只能找到第一个include的layout布局,以及该布局的控件
3,若是咱们给include所加载的layout布局的根容器设置了id属性,也在include标签中设置了id属性,同时须要在代码中获取根容器的控件对象
时,最好将这两个id设置相同的名称!不然,可能获取不到根容器对象,即为null。

2、merge的用法以及注意点

merge标签存在的意义是帮助include标签排除多余的一层ViewGroup容器,减小view hierarchy的结构,提高UI渲染的性能。include标签存在着一个很差的地方,可能会致使产生多余的布局嵌套。一样经过一个小demo来讲明:优化

好比项目中有一个公共的登陆按钮布局,以下:spa

login.xml:code

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="wrap_content"
 5     android:orientation="vertical" >
 6     
 7      <Button  8         android:layout_width="match_parent"  
 9         android:layout_height="wrap_content"  
10         android:layout_marginLeft="20dp"  
11         android:layout_marginRight="20dp"  
12         android:text="登陆按钮" />  
13     
14 </LinearLayout>

很简单,就是一个登陆的Button。

项目中有登陆功能的UI界面以下:

activity_login.xml:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical"
 6     android:background="@android:color/holo_blue_light">
 7 
 8     <EditText  9         android:layout_width="match_parent"  
10         android:layout_height="wrap_content" 
11         android:layout_marginLeft="20dp"  
12         android:layout_marginRight="20dp"  
13         android:layout_marginTop="40dp"  
14         android:hint="请输入用户名" />
15     
16     <include layout="@layout/login" />
17 
18 </LinearLayout>

一样很是简单,运行程序,以下:

 

看起来没什么问题,其实不知不觉中咱们多嵌套了一层布局。咱们用工具查看一下此时布局结构:

除去系统布局,咱们本身布局最外层是LinearLayout,而后两个并列布局EditText与LinearLayout,在LinearLayout里面是Button登陆按钮。

其实这种状况下:在主界面中,<include>标签的parent ViewGroup与包含的layout根容器ViewGroup是相同的类型,这里都是LinearLayout,那么则能够将包含的layout根容器ViewGroup使用<merge>标签代替,从而减小一层ViewGroup的嵌套,提高UI渲染性能。

这里咱们把activity_login.xml修改以下:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <merge xmlns:android="http://schemas.android.com/apk/res/android">
 3     
 4      <Button  5         android:layout_width="match_parent"  
 6         android:layout_height="wrap_content"  
 7         android:layout_marginLeft="20dp"  
 8         android:layout_marginRight="20dp"  
 9         android:text="登陆按钮" />  
10     
11 </merge>

从新运行程序UI和上面同样效果,经过工具再次查看布局结构;

看到了吧,咱们本身布局减小了一层嵌套,从而提高了UI的渲染速度。

merge标签使用注意点:

1,根布局是FrameLayout且不须要设置background或padding等属性,能够用merge代替,由于Activity的ContentView父元素就是FrameLayout,因此能够用merge消除只剩一个.

2,由于merge标签并非View,因此在经过LayoutInflate.inflate()方法渲染的时候,第二个参数必须指定一个父容器,且第三个参数必须为true,也就是必须为merge下的视图指定一个父亲节点.因为merge不是View因此对merge标签设置的全部属性都是无效的.

LayoutInflate中源码体现:

 1     public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {  2         synchronized (mConstructorArgs) {  3             
 4  ...  5 
 6                 if (TAG_MERGE.equals(name)) {  7                     if (root == null || !attachToRoot) {  8                         throw new InflateException("<merge /> can be used only with a valid "
 9                                 + "ViewGroup root and attachToRoot=true"); 10  } 11 
12                     rInflate(parser, root, inflaterContext, attrs, false); 13  } 14  ... 15  } 16     }

3,merge标签必须使用在根布局,而且ViewStub标签中的layout布局不能使用merge标签.

ViewStub的用法以及注意点

ViewStub也能够用来加载布局文件,但与include标签彻底不一样。ViewStub是一个不可见的View类,用于在运行时按需懒加载资源,只有在代码中调用了viewStub.inflate()或者viewStub.setVisible(View.visible)方法时才内容才变得可见。这里须要注意的一点是,当ViewStub被inflate到parent时,ViewStub就被remove掉了,即当前view hierarchy中再也不存在ViewStub,而是使用对应的layout视图代替。

一样咱们经过一个小demo说明一下,好比咱们须要保存一个用户信息,用户名是必须保存的,可是其他信息是没必要要的,这是其他信息就能够一开始不显示出来,用户想输入的时候在现实出来。

其他信息布局以下:

otherinfo.xml:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:orientation="vertical"
 5     android:layout_height="wrap_content" >
 6 
 7     <EditText  8         android:id="@+id/weichat_id"
 9         android:layout_width="match_parent"
10         android:layout_height="wrap_content"
11         android:layout_marginLeft="20dp"
12         android:layout_marginRight="20dp"
13         android:layout_marginTop="10dp"
14         android:hint="请输入微信号" />
15 
16     <EditText 17         android:id="@+id/address_id"
18         android:layout_width="match_parent"
19         android:layout_height="wrap_content"
20         android:layout_marginLeft="20dp"
21         android:layout_marginRight="20dp"
22         android:layout_marginTop="10dp"
23         android:hint="请输入家庭住址" />
24 
25 </LinearLayout>

很简单,没什么其他解释的,主界面布局以下:

activity_main.xml:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:background="@android:color/holo_blue_light"
 6     android:orientation="vertical" >
 7 
 8     <EditText  9         android:layout_width="match_parent"
10         android:layout_height="wrap_content"
11         android:layout_marginLeft="20dp"
12         android:layout_marginRight="20dp"
13         android:layout_marginTop="40dp"
14         android:hint="请输入用户名" />
15 
16     <ViewStub 17         android:id="@+id/viewstub"
18         android:layout_width="match_parent"
19         android:layout_height="wrap_content"
20         android:layout="@layout/otherinfo" />
21 
22     <Button 23         android:layout_width="match_parent"
24         android:layout_height="wrap_content"
25         android:onClick="show"
26         android:layout_marginLeft="20dp"
27         android:layout_marginRight="20dp"
28         android:layout_marginTop="10dp"
29         android:text="显示" />
30 
31 </LinearLayout>

其他信息界面经过ViewStub引入进来,关于ViewStub主要属性以及方法说明以下:

    • android:layout属性
      加载包含的layout布局文件;

    • android:inflatedId属性
      重写包含的layout布局文件的根容器id;

    • inflate()方法
      setVisible(int)方法做用相似,均可以使内容得以显示,只是inflate()会返回一个View对象,避免了额外使用findViewById()方法获取layout视图对象。

activity中代码以下:

1 public void show(View view){ 2         // 3         ViewStub stub = ((ViewStub) findViewById(R.id.viewstub)); 4         if(stub!=null){ 5             View stubView = stub.inflate(); 6             EditText address = (EditText) stubView.findViewById(R.id.address_id); 7             EditText wechatId = (EditText) stubView.findViewById(R.id.weichat_id); 8  } 9     }

好了,运行程序,一开始以下:

点击显示按钮,UI以下:

 ViewStub标签使用注意点:

1,ViewStub标签不支持merge标签。所以这有可能致使加载出来的布局存在着多余的嵌套结构,具体如何去取舍就要根据各自的实际状况来决定了。

2,ViewStub的inflate只能被调用一次,第二次调用会抛出异常。

3,虽然ViewStub是不占用任何空间的,可是每一个布局都必需要指定layout_width和layout_height属性,不然运行就会报错。

好了,以上就是我的对于include 、merge、ViewStub使用的总结,但愿对你有用,即便已经掌握,但愿读完此文能温故知新。

相关文章
相关标签/搜索