1. 程式人生 > >Android最佳效能實踐——佈局優化技巧之、標籤及僅在需要時才載入佈局的:ViewStub

Android最佳效能實踐——佈局優化技巧之、標籤及僅在需要時才載入佈局的:ViewStub

在前面幾篇文章當中,我們學習瞭如何通過合理管理記憶體,以及高效能編碼技巧的方式來提升應用程式的效能。然而實際上介面佈局也會對應用程式的效能產生比較大的影響,如果佈局寫得糟糕的話,那麼程式載入UI的速度就會非常慢,從而造成不好的使用者體驗。那麼本篇文章我們就來學習一下,如何通過優化佈局來提供應用程式的效能。還沒有看過前面前面一篇文章的朋友建議可以先去閱讀 Android最佳效能實踐(三)——高效能編碼優化 。

重用佈局檔案

Android系統中已經提供了非常多好用的控制元件,這讓我們在編寫佈局的時候可以很輕鬆。但是有些時候我們可能需要反覆利用某個已經寫好的佈局,如果你總是使用複製貼上的方式來進行佈局重用,這顯然是一種很笨的做法。而Android當然也已經充分考慮到了佈局重用的重要性,於是提供了<include>和<merge>這兩個非常有用的標籤,下面我們就來逐個學習一下。

<include>

<include>標籤可以允許在一個佈局當中引入另外一個佈局,那麼比如說我們程式的所有介面都有一個公共的部分,這個時候最好的做法就是將這個公共的部分提取到一個獨立的佈局檔案當中,然後在每個介面的佈局檔案當中來引用這個公共的佈局。

這裡舉個例子吧,我們應該都知道,目前幾乎所有的軟體都會有一個頭佈局,頭佈局中可以包含介面的標題、返回按鈕、以及其它一些操作功能等。那這樣的一個頭佈局,有些軟體是使用ActionBar來實現的,但是由於ActionBar的靈活性不太好,因而也有很多軟體會選擇自己去編寫實現。那如果自己去實現的話,由於這個頭佈局是在所有介面都要使用的,顯然我們不可能在每個介面當中都去寫一遍這個頭佈局的程式碼,因此這種情況下使用<include>標籤就非常合適了。這裡為了給大家演示一下,我就編寫一個非常簡單的頭佈局,在res/layout資料夾中新建titlebar.xml作為頭佈局,程式碼如下所示:

  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent">
  5.     <Button
  6.         android:id="@+id/back"
  7.         android:layout_width="wrap_content"
  8.         android:layout_height="wrap_content"
  9.         android:layout_alignParentLeft="true"
  10.         android:layout_centerVertical="true"
  11.         android:text="Back"/>
  12.     <TextView
  13.         android:id="@+id/title"
  14.         android:layout_width="wrap_content"
  15.         android:layout_height="wrap_content"
  16.         android:layout_centerInParent="true"
  17.         android:text="Title"
  18.         android:textSize="20sp"/>
  19.     <Button
  20.         android:id="@+id/done"
  21.         android:layout_width="wrap_content"
  22.         android:layout_height="wrap_content"
  23.         android:layout_alignParentRight="true"
  24.         android:layout_centerVertical="true"
  25.         android:text="Done"/>
  26. </RelativeLayout>
可以看到,titlebar.xml中的佈局非常簡單,外層是一個RelativeLayout,裡面只有兩個Button和一個TextView,左邊的Button用於實現返回功能,右邊的Button用於實現完成功能,中間的TextView則可以用於顯示當前介面的標題。我們可以來預覽一下titlebar的樣子,如下圖所示:


好的,那titlebar作為一個獨立的佈局現在我們已經編寫完了,接下來的工作就非常簡單了,無論任何介面需要加入titlebar這個功能,只需要在佈局檔案中引入titlebar.xml就可以了。那麼比如說我們的程式當中有一個activity_main.xml檔案,現在想要引入titlebar只需要這樣寫:

  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     android:orientation="vertical">
  6.     <includelayout="@layout/titlebar"/>
  7.     ......  
  8. </LinearLayout>
非常簡單吧,一行include語句就可以搞定了。<include>標籤當中可以指定一個layout屬性,我們在這個layout屬性中填寫需要引入的佈局名就可以了。而且使用這種引入的方式,以後如果titlebar的介面有所變更,我們只需要修改titlebar.xml這一個檔案就可以了,而不是所有介面一個個地去修改。

等等!現在如果你執行一下程式會發現出大問題了,雖然titlebar是成功引入了,但是我們activity_main.xml中本來的介面全部都不見了!出現這個問題是原因是因為titlebar的最外層佈局是一個寬高都是match_parent的RelativeLayout,它會將整個佈局都填充滿,因而我們原本的佈局也就看不見了。那既然問題的原因清楚了,相信你立刻就想到應該怎麼修改了,將RelativeLayout的layout_height屬性修改成wrap_content不就可以了嘛。沒錯,這樣修改當然是沒問題的,不過這種修改方式會讓所有引用titlebar的介面都受到影響,而如何你只希望讓activity_main.xml這一個介面受影響的話,那麼可以使用覆寫<include>屬性的方式。

在<include>標籤當中,我們是可以覆寫所有layout屬性的,即include中指定的layout屬性將會覆蓋掉titlebar中指定的layout屬性。因此,這裡我們希望將titlebar的高度設定成wrap_content,就可以這樣寫:

  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     android:orientation="vertical">
  6.     <include
  7.         android:layout_width="match_parent"
  8.         android:layout_height="wrap_content"
  9.         layout="@layout/titlebar"/>
  10.     ......  
  11. </LinearLayout>
現在重新執行一下程式應該就可以一切正常了,如下圖所示:


除了layout_height之外,我們還可以覆寫titlebar中的任何一個layout屬性,如layout_gravity、layout_margin等,而非layout屬性則無法在<include>標籤當中進行覆寫。另外需要注意的是,如果我們想要在<include>標籤當中覆寫layout屬性,必須要將layout_width和layout_height這兩個屬性也進行覆寫,否則覆寫效果將不會生效。

<merge>

<merge>標籤是作為<include>標籤的一種輔助擴充套件來使用的,它的主要作用是為了防止在引用佈局檔案時產生多餘的佈局巢狀。大家都知道,Android去解析和展示一個佈局是需要消耗時間的,佈局巢狀的越多,那麼解析起來就越耗時,效能也就越差,因此我們在編寫佈局檔案時應該讓巢狀的層數越少越好。

在上面我們講解<include>標籤的用法時主要介紹了它優點,但是它也存在著一個不好的地方,就是可能會導致產生多餘的佈局巢狀。這裡還是通過舉例的方式跟大家說明一下,比如說我們需要編寫一個確定取消按鈕的公共佈局,這樣任何一個介面需要確定和取消功能時就不用再單獨編寫了,新建ok_cancel_layout.xml,程式碼如下所示:

  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns: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.     <Button
  7.         android:id="@+id/ok"
  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="OK"/>
  13.     <Button
  14.         android:id="@+id/cancel"
  15.         android:layout_width="match_parent"
  16.         android:layout_height="wrap_content"
  17.         android:layout_marginLeft="20dp"
  18.         android:layout_marginRight="20dp"
  19.         android:layout_marginTop="10dp"
  20.         android:text="Cancel"/>
  21. </LinearLayout>
可以看到,這個介面也是非常簡單,外層是一個垂直方向的LinearLayout,LinearLayout中包含了兩個按鈕,一個用於實現確定功能,一個用於實現取消功能。現在我們可以來預覽一下這個介面,如下圖所示:


好的,然後我們有一個profile.xml的介面需要編輯一些內容,那麼這裡就可以將ok_cancel_layout這個佈局引入到profile.xml介面當中,如下所示: