前言
本篇文章為Android優(yōu)化的布局部分炒刁,該部分應(yīng)該是Android中很重要的仔雷,無論是在自定義控件中冷溶,還是在簡單的書寫布局時院刁,都應(yīng)該盡量遵循一些優(yōu)化原則糯钙,這樣布局的繪制效率才會更高,體驗才能更好退腥。
一 優(yōu)化layout的層級
Layout結(jié)構(gòu)如果太復(fù)雜任岸,Android的繪制過程就會很復(fù)雜,measure過程就會很復(fù)雜狡刘,我分析的View繪制機(jī)制中詳細(xì)介紹了整個測量享潜、布局和繪制過程,過于復(fù)雜嗅蔬、嵌套的布局會造成性能問題剑按。
1.1 避免嵌套
嵌套的 LinearLayout 可能會使得 View 的層級結(jié)構(gòu)很深。使用LinearLayout時澜术,通常我們喜歡用嵌套的布局來動態(tài)設(shè)置一個View的Visibility 艺蝴,由于LinearLayout是線性的,因此即使隱藏一個View也不會影響到其它View的排列鸟废。而在RelativeLayout中猜敢,View的位置都是相對于其它View的,因此,隱藏之后缩擂,會導(dǎo)致之前的View沒有參考對象了鼠冕,導(dǎo)致的相對位置改變,這時你可以使用alignWithParentIfMissing=”true”來處理這種情況撇叁。
此外供鸠,嵌套使用了 layout_weight 參數(shù)的 LinearLayout 的計算量會尤其大畦贸,因為每個子元素都需要被測量兩次陨闹。這對需要多次重復(fù) inflate 的 Layout 尤其需要注意,比如使用 ListView 或 GridView 時薄坏。
1.2 使用merge標(biāo)簽優(yōu)化層級
在使用了include后可能導(dǎo)致布局嵌套過多趋厉,出現(xiàn)不必要的layout節(jié)點,從而導(dǎo)致解析變慢胶坠。
merge標(biāo)簽可用于兩種典型情況:
布局頂結(jié)點是FrameLayout且不需要設(shè)置background或padding等屬性君账,可以用merge代替,因為Activity內(nèi)容試圖的parent view就是個FrameLayout沈善,所以可以用merge消除只剩一個乡数。
某布局作為子布局被其他布局include時,使用merge當(dāng)作該布局的頂節(jié)點闻牡,這樣在被引入時頂結(jié)點會自動被忽略净赴,而將其子節(jié)點全部合并到主布局中。
比如罩润,如果你有一個 Layout 是一個豎直方向的 LinearLayout玖翅,其中包含兩個連續(xù)的 View 可以在別的 Layout 中重用,那么你會做一個 LinearLayout 來包含這兩個 View 割以,以便重用金度。不過,當(dāng)使用另一個 LinearLayout 來嵌套這個可重用的 LinearLayout 時严沥,這種嵌套 LinearLayout 的方式除了減慢你的 UI 性能外沒有任何意義猜极。
為了避免這種情況,你可以用 元素來替代可重用 Layout 的根節(jié)點消玄。例如:
<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>
現(xiàn)在跟伏,當(dāng)你要將這個 Layout 包含到另一個 Layout 中時(并且使用了 標(biāo)簽),系統(tǒng)會直接把兩個 Button 放到 Layout 中莱找,而不會有多余的 Layout 被嵌套酬姆。
二 使用標(biāo)簽重用Layout
如果你的程序 UI 在不同地方重復(fù)使用某個 Layout,那本節(jié)教你如何創(chuàng)建高效的奥溺,可重用的 Layout 部件辞色,并把它們“包含”到 UI Layout 中。
為了高效重用整個的 Layout浮定,你可以使用 和 標(biāo)簽把其他 Layout 嵌入當(dāng)前 Layout相满。
三 按需載入視圖
除了簡單的把一個 Layout 包含到另一個中层亿,你可能還想在程序開始后,僅當(dāng)你的 Layout 對用戶可見時才開始載入立美。
3.1 不需要立即加載的布局匿又,設(shè)置為GONE,系統(tǒng)會跳過建蹄,不加載
3.2 使用ViewStub 實現(xiàn)按需加載
ViewStub 是一個輕量的視圖碌更,不需要大小信息,也不會在被加入的 Layout 中繪制任何東西洞慎。每個 ViewStub 只需要設(shè)置 android:layout 屬性來指定需要被 inflate 的 Layout 類型痛单。viewstub常用來引入那些默認(rèn)不會顯示,只在特殊情況下顯示的布局劲腿,如進(jìn)度布局旭绒、網(wǎng)絡(luò)失敗顯示的刷新布局、信息出錯出現(xiàn)的提示布局等焦人。
以下 ViewStub 是一個半透明的進(jìn)度條覆蓋層挥吵。功能上講,它應(yīng)該只在新的數(shù)據(jù)項被導(dǎo)入到應(yīng)用程序時可見花椭。
<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當(dāng)你要載入用 ViewStub 聲明的 Layout 時忽匈,要么用 setVisibility(View.VISIBLE) 設(shè)置它的可見性,要么調(diào)用其 inflate() 方法个从。
下面以在一個布局main.xml中加入網(wǎng)絡(luò)錯誤時的提示頁面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為只有在網(wǎng)絡(luò)錯誤時才需要顯示的布局
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 的視圖,所以你不需要再調(diào)用 findViewById() 去查找這個元素嗦锐。減少inflate的次數(shù),也會對效率有一點提升嫌松。而setVisible方式還需要再次findViewById找到ViewStub中的元素。
一旦 ViewStub 可見或是被 inflate 了奕污,ViewStub 元素就不存在了萎羔。取而代之的是被 inflate 的 Layout,其 id 是 ViewStub 上的 android:inflatedId 屬性碳默。(ViewStub 的 android:id 屬性僅在 ViewStub 可見以前可用)
注意:ViewStub 的一個缺陷是贾陷,它目前不支持使用 標(biāo)簽的 Layout
四 ListView的優(yōu)化
如果你有一個包含復(fù)雜或者每個項 (item) 包含很多數(shù)據(jù)的 ListView ,那么上下滾動的性能可能會降低嘱根。本節(jié)給你一些關(guān)于如何把滾動變得更流暢的提示髓废。保持程序流暢的關(guān)鍵,是讓主線程(UI 線程)不要進(jìn)行大量運算该抒。你要確保在其他線程執(zhí)行磁盤讀寫慌洪、網(wǎng)絡(luò)讀寫或是 SQL 操作等。為了測試你的應(yīng)用的狀態(tài),你可以啟用 StrictMode冈爹。
4.1 使用后臺線程
你應(yīng)該把主線程中的耗時間的操作涌攻,提取到一個后臺線程中,使得主線程只關(guān)注 UI 繪畫频伤。
4.2 在 View Holder 中填入視圖對象
使用convertView恳谎、你的代碼可能在 ListView 滑動時經(jīng)常使用 findViewById(),這樣會降低性能憋肖。即使是 Adapter 返回一個用于回收的 convertView因痛,你仍然需要查找這個元素并更新它。避免頻繁調(diào)用 findViewById() 的方法之一瞬哼,就是使用 View Holder(視圖占位符)設(shè)計模式婚肆。
ViewHolder 存儲了標(biāo)簽下的每個視圖。這樣你不用頻繁查找這個元素:
static class ViewHolder {
TextView text; TextView timestamp; ImageView icon;
ProgressBar progress; int position;
}
然后坐慰,在 Layout 的類中生成一個 ViewHolder 對象:
javaViewHolder holder = new ViewHolder();
holder.icon = (ImageView) convertView.findViewById(R.id.listitem_image);
...convertView.setTag(holder);
這樣你就可以輕松獲取每個視圖,而不是用 findViewById() 來不斷查找視圖用僧,節(jié)省了寶貴的運算時間结胀。
4.3 getView不要做復(fù)雜的操作
因為每一條Item移入屏幕的時候,都會調(diào)用getView责循,不要在getView中做復(fù)雜的操作糟港,不要頻繁的創(chuàng)建對象。Item點擊的處理不要提前做院仿。特別是在快速滑動的時候秸抚,會導(dǎo)致頻繁的調(diào)用getView。
五 優(yōu)化提示
盡量使用RelativeLayout歹垫,可以減少層級的嵌套剥汤。慎用LinearLayout的layout_weight屬性,可以使用RelativeLayout的centerHorizontal=”true”排惨、toLeft吭敢、toRight代替
六 書寫規(guī)范上的優(yōu)化
6.1 Id的命名
為了便于識別,你可以根據(jù)自己的業(yè)務(wù)來對當(dāng)前界面的資源進(jìn)行命名暮芭,比如當(dāng)前是登陸界面鹿驼,那么你可以這樣命名:login_edit_usernamelogin_edit_passwordlogin_btn_submitlogin_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等,規(guī)范通用的命名可以很方便的移植到其它項目中瑞筐。
<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>
轉(zhuǎn)載自:
http://www.lightskystreet.com/2015/01/19/android-layout-optimize/
參考文獻(xiàn)
best-practices-for-android-user-interface
layout-performance