Android布局最佳化

來源:互聯網
上載者:User

標籤:

前言

本篇文章為Android最佳化的布局部分,該部分應該是Android中很重要的,無論是在自訂控制項中,還是在簡單的書寫布局時,都應該盡量遵循一些最佳化原則,這樣布局的繪製效率才會更高,體驗才能更好。

最佳化layout的層級

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

1.1 避免嵌套

嵌套的 LinearLayout 可能會使得 View 的層級結構很深。使用LinearLayout時,通常我們喜歡用嵌套的布局來動態設定一個View的Visibility ,由於LinearLayout是線性,因此即使隱藏一個View也不會影響到其它View的排列。而在RelativeLayout中,View的位 置都是相對於其它View的,因此,隱藏之後,會導致之前的View沒有參考對象了,導致的相對位置改變,這時你可以使用 alignWithParentIfMissing=”true”來處理這種情況。

此外,嵌套使用了 layout_weight 參數的 LinearLayout 的計算量會尤其大,因為每個子項目都需要被測量兩次。這對需要多次重複 inflate 的 Layout 尤其需要注意,比如使用 ListView 或 GridView 時。

1.2 使用merge標籤最佳化層級

在使用了include後可能導致布局嵌套過多,出現不必要的layout節點,從而導致解析變慢。

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

  • 布局頂結點是FrameLayout且不需要設定background或padding等屬性,可以用merge代替,因為Activity內容試圖的parent view就是個FrameLayout,所以可以用merge消除只剩一個。
  • 某布局作為子布局被其他布局include時,使用merge當作該布局的頂節點,這樣在被引入時頂結點會自動被忽略,而將其子節點全部合并到主布局中。

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

為了避免這種情況,你可以用  元素來替代可重用 Layout 的根節點。例如:

 

<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 是一個半透明的進度條覆蓋層。功能上講,它應該只在新的資料項目被匯入到應用程式時可見。

 

<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代碼如下:

 

<?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)方式

 

View viewStub = ((ViewStub)findViewById(R.id.stub_import));

viewStub.setVisibility(View.VISIBLE);

netErrorLayout = findViewById(R.id.net_error_layout))

inflate方式

 

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 儲存了標籤下的每個視圖。這樣你不用頻繁尋找這個元素:

 

static class ViewHolder {

    TextView text;

    TextView timestamp;

    ImageView icon;

    ProgressBar progress;

    int position;

}

然後,在 Layout 的類中產生一個 ViewHolder 對象:

 

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等,規範通用的命名可以很方便的移植到其它項目中。

 

<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

 轉載自  lightSky的部落格 Android布局最佳化 

Android布局最佳化

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.