Android布局優(yōu)化

前言
本篇文章為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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凄鼻,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌野宜,老刑警劉巖扫步,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異匈子,居然都是意外死亡河胎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門虎敦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來游岳,“玉大人,你說我怎么就攤上這事其徙∨咂龋” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵唾那,是天一觀的道長访锻。 經(jīng)常有香客問我,道長闹获,這世上最難降的妖魔是什么期犬? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮避诽,結(jié)果婚禮上龟虎,老公的妹妹穿的比我還像新娘。我一直安慰自己沙庐,他們只是感情好鲤妥,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拱雏,像睡著了一般棉安。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上古涧,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天垂券,我揣著相機(jī)與錄音,去河邊找鬼羡滑。 笑死菇爪,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的柒昏。 我是一名探鬼主播凳宙,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼职祷!你這毒婦竟也來了氏涩?” 一聲冷哼從身側(cè)響起届囚,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎是尖,沒想到半個月后意系,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡饺汹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年蛔添,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兜辞。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡迎瞧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出逸吵,到底是詐尸還是另有隱情凶硅,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布扫皱,位于F島的核電站足绅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏啸罢。R本人自食惡果不足惜编检,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望扰才。 院中可真熱鬧,春花似錦厕怜、人聲如沸衩匣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽琅捏。三九已至,卻和暖如春递雀,著一層夾襖步出監(jiān)牢的瞬間柄延,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工缀程, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留搜吧,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓杨凑,卻偏偏與公主長得像滤奈,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子撩满,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容