Android佈局優化

前言

本篇文章爲Android優化的佈局部分,該部分應該是Android中很重要的,不管是在自定義控件中,仍是在簡單的書寫佈局時,都應該儘可能遵循一些優化原則,這樣佈局的繪製效率纔會更高,體驗才能更好。
java

一 優化layout的層級

Layout結構若是太複雜,Android的繪製過程就會很複雜,measure過程就會很複雜,我分析的View繪製機制中詳細介紹了整個測量、佈局和繪製過程,過於複雜、嵌套的佈局會形成性能問題。android

1.1 避免嵌套

嵌套的 LinearLayout 可能會使得 View 的層級結構很深。使用LinearLayout時,一般咱們喜歡用嵌套的佈局來動態設置一個View的Visibility ,因爲LinearLayout是線性的,所以即便隱藏一個View也不會影響到其它View的排列。而在RelativeLayout中,View的位置都是相對於其它View的,所以,隱藏以後,會致使以前的View沒有參考對象了,致使的相對位置改變,這時你可使用alignWithParentIfMissing=」true」來處理這種狀況。git

此外,嵌套使用了 layout_weight 參數的 LinearLayout 的計算量會尤爲大,由於每一個子元素都須要被測量兩次。這對須要屢次重複 inflate 的 Layout 尤爲須要注意,好比使用 ListView 或 GridView 時。github

1.2 使用merge標籤優化層級

在使用了include後可能致使佈局嵌套過多,出現沒必要要的layout節點,從而致使解析變慢。設計模式

merge標籤可用於兩種典型狀況:api

  • 佈局頂結點是FrameLayout且不須要設置background或padding等屬性,能夠用merge代替,由於Activity內容試圖的parent view就是個FrameLayout,因此能夠用merge消除只剩一個。
  • 某佈局做爲子佈局被其餘佈局include時,使用merge看成該佈局的頂節點,這樣在被引入時頂結點會自動被忽略,而將其子節點所有合併到主佈局中。

好比,若是你有一個 Layout 是一個豎直方向的 LinearLayout,其中包含兩個連續的 View 能夠在別的 Layout 中重用,那麼你會作一個 LinearLayout 來包含這兩個 View ,以便重用。不過,當使用另外一個 LinearLayout 來嵌套這個可重用的 LinearLayout 時,這種嵌套 LinearLayout 的方式除了減慢你的 UI 性能外沒有任何意義。網絡

爲了不這種狀況,你能夠用  元素來替代可重用 Layout 的根節點。例如: 佈局

       
       
       
       
1
2
3
4
5
6
7
8
9
10
11
12
13
       
       
       
       
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:layout_width= "fill_parent"
android:layout_height= "wrap_content"
android:text= "@string/add"/>
<Button
android:layout_width= "fill_parent"
android:layout_height= "wrap_content"
android:text= "@string/delete"/>
</merge>

如今,當你要將這個 Layout 包含到另外一個 Layout 中時(而且使用了  標籤),系統會直接把兩個 Button 放到 Layout 中,而不會有多餘的 Layout 被嵌套。 性能

二 使用 標籤重用Layout

若是你的程序 UI 在不一樣地方重複使用某個 Layout,那本節教你如何建立高效的,可重用的 Layout 部件,並把它們「包含」到 UI Layout 中。測試

爲了高效重用整個的 Layout,你可使用  和  標籤把其餘 Layout 嵌入當前 Layout。

三 按需載入視圖

除了簡單的把一個 Layout 包含到另外一箇中,你可能還想在程序開始後,僅當你的 Layout 對用戶可見時纔開始載入。

3.1 不須要當即加載的佈局,設置爲GONE,系統會跳過,不加載

3.2 使用ViewStub 實現按需加載

ViewStub 是一個輕量的視圖,不須要大小信息,也不會在被加入的 Layout 中繪製任何東西。每一個 ViewStub 只須要設置 android:layout 屬性來指定須要被 inflate 的 Layout 類型。viewstub經常使用來引入那些默認不會顯示,只在特殊狀況下顯示的佈局,如進度佈局、網絡失敗顯示的刷新佈局、信息出錯出現的提示佈局等。

如下 ViewStub 是一個半透明的進度條覆蓋層。功能上講,它應該只在新的數據項被導入到應用程序時可見。

       
       
       
       
1
2
3
4
5
6
7
       
       
       
       
<ViewStub
android:id= "@+id/stub_import"
android:inflatedId= "@+id/panel_import"
android:layout= "@layout/progress_overlay"
android:layout_width= "fill_parent"
android:layout_height= "wrap_content"
android:layout_gravity= "bottom" />

載入 ViewStub
當你要載入用 ViewStub 聲明的 Layout 時,要麼用 setVisibility(View.VISIBLE) 設置它的可見性,要麼調用其 inflate() 方法。

下面以在一個佈局main.xml中加入網絡錯誤時的提示頁面network_error.xml爲例。main.mxl代碼以下:

       
       
       
       
1
2
3
4
5
6
7
8
9
10
11
12
13
       
       
       
       
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width= "match_parent"
android:layout_height= "match_parent" >
……
<ViewStub
android:id= "@+id/network_error_layout"
android:layout_width= "match_parent"
android:layout_height= "match_parent"
android:layout= "@layout/network_error" />
</RelativeLayout>

其中network_error.xml爲只有在網絡錯誤時才須要顯示的佈局

setVisibility(View.VISIBLE)方式

       
       
       
       
1
2
3
       
       
       
       
View viewStub = ((ViewStub)findViewById(R.id.stub_import));
viewStub.setVisibility(View.VISIBLE);
netErrorLayout = findViewById(R.id.net_error_layout))

inflate方式

       
       
       
       
1
       
       
       
       
View netErrorLayout = ((ViewStub) findViewById(R.id.net_error_layout)).inflate();

注意:
inflate() 方法會在渲染完成後返回給被 inflate 的視圖,因此你不須要再調用 findViewById() 去查找這個元素。減小inflate的次數,也會對效率有一點提高。
而setVisible方式還須要再次findViewById找到ViewStub中的元素。

一旦 ViewStub 可見或是被 inflate 了,ViewStub 元素就不存在了。取而代之的是被 inflate 的 Layout,其 id 是 ViewStub 上的 android:inflatedId 屬性。(ViewStub 的 android:id 屬性僅在 ViewStub 可見之前可用)

注意:ViewStub 的一個缺陷是,它目前不支持使用  標籤的 Layout

四 ListView的優化

若是你有一個包含複雜或者每一個項 (item) 包含不少數據的 ListView ,那麼上下滾動的性能可能會下降。本節給你一些關於如何把滾動變得更流暢的提示。
保持程序流暢的關鍵,是讓主線程(UI 線程)不要進行大量運算。你要確保在其餘線程執行磁盤讀寫、網絡讀寫或是 SQL 操做等。爲了測試你的應用的狀態,你能夠啓用 StrictMode。

4.1 使用後臺線程

你應該把主線程中的耗時間的操做,提取到一個後臺線程中,使得主線程只關注 UI 繪畫。

4.2 在 View Holder 中填入視圖對象

使用convertView、
你的代碼可能在 ListView 滑動時常用 findViewById(),這樣會下降性能。即便是 Adapter 返回一個用於回收的 convertView,你仍然須要查找這個元素並更新它。避免頻繁調用 findViewById() 的方法之一,就是使用 View Holder(視圖佔位符)設計模式。

ViewHolder 存儲了標籤下的每一個視圖。這樣你不用頻繁查找這個元素:

       
       
       
       
1
2
3
4
5
6
7
       
       
       
       
static class ViewHolder {
TextView text;
TextView timestamp;
ImageView icon;
ProgressBar progress;
int position;
}

而後,在 Layout 的類中生成一個 ViewHolder 對象:

       
       
       
       
1
2
3
4
       
       
       
       
ViewHolder holder = new ViewHolder();
holder.icon = (ImageView) convertView.findViewById(R.id.listitem_image);
...
convertView.setTag(holder);

這樣你就能夠輕鬆獲取每一個視圖,而不是用 findViewById() 來不斷查找視圖,節省了寶貴的運算時間。

4.3 getView不要作複雜的操做

由於每一條Item移入屏幕的時候,都會調用getView,不要在getView中作複雜的操做,不要頻繁的建立對象。Item點擊的處理不要提早作。特別是在快速滑動的時候,會致使頻繁的調用getView。

五 優化提示

儘可能使用RelativeLayout,能夠減小層級的嵌套。
慎用LinearLayout的layout_weight屬性,可使用RelativeLayout的centerHorizontal=」true」、toLeft、toRight代替

六 書寫規範上的優化

6.1 Id的命名

爲了便於識別,你能夠根據本身的業務來對當前界面的資源進行命名,好比當前是登錄界面,那麼你能夠這樣命名:
login_edit_username
login_edit_password
login_btn_submit
login_txv_forgot_pass

6.2 資源的命名

ic_action_add, ic_action_location (ActionBar Icons)
ic_play, ic_save (General Icons)
ic_tab_music, ic_tab_more (Tab Icons)

6.3 通用的資源命名

對style.xml和dimens.xml的命名能夠通用的儘可能通用,由於一個項目的基本視圖不少都是通用的,好比ActionBar、ListView等,規範通用的命名能夠很方便的移植到其它項目中。

       
       
       
       
1
2
3
4
5
6
7
8
9
10
11
12
       
       
       
       
<color name="list_item_large">#FCA558 </color>
<color name="list_item_small">#FBA228 </color>
<dimen name="list_item_large">24dp </dimen>
<dimen name="list_item_small">18dp </dimen>
<!-- 簡單ListView樣式 -->
<style name="list_view_style_default">
< item name=" android :layout_width"> fill_parent</ item>
< item name=" android :layout_height"> wrap_content</ item>
...
</style>

參考文獻

best-practices-for-android-user-interface
layout-performance

via :    http://www.lightskystreet.com/2015/01/19/android-layout-optimize/
相關文章
相關標籤/搜索