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使用的總結,但願對你有用,即便已經掌握,但願讀完此文能溫故知新。

相關文章
相關標籤/搜索