Android布局優(yōu)化之ViewStub冻璃、include、merge

在開發(fā)中UI布局是我們都會遇到的問題,隨著UI越來越多省艳,布局的重復(fù)性娘纷、復(fù)雜度也會隨之增長。對此我們優(yōu)化xml布局就不得不說重用布局跋炕,為了有效地重新使用完整的布局赖晶,Google提出可以使用<include>和<merge>這兩個(gè)非常有用的標(biāo)簽,用以在當(dāng)前布局中嵌入另一個(gè)布局辐烂,下面我們就來逐個(gè)學(xué)習(xí)一下遏插。

一、include

<include/>標(biāo)簽可以允許在一個(gè)布局當(dāng)中引入另外一個(gè)布局纠修,那么比如說我們程序的所有界面都有一個(gè)公共的部分胳嘲,這個(gè)時(shí)候最好的做法就是將這個(gè)公共的部分提取到一個(gè)獨(dú)立的布局文件當(dāng)中,然后在每個(gè)界面的布局文件當(dāng)中來引用這個(gè)公共的布局扣草。這里舉個(gè)例子吧了牛,例如在include_layout.xml添加兩個(gè)按鈕:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button One"
        android:id="@+id/button" />
    <Button
        android:layout_width="match_parent" 
       android:layout_height="wrap_content"
        android:text="Button Two"
        android:id="@+id/button2" />
</LinearLayout>

好的,那這連個(gè)按鈕作為一個(gè)獨(dú)立的布局現(xiàn)在我們已經(jīng)編寫完了辰妙,接下來的工作就非常簡單了白魂,無論任何界面需要加入這個(gè)布局,只需要在布局文件中引入include_layout.xml就可以了上岗。那么比如說我們的程序當(dāng)中有一個(gè)activity_main.xml文件福荸,現(xiàn)在想要引入include_layout.xml只需要這樣寫:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button"
        android:onClick="onClick"
        android:id="@+id/button1"/>
    <include layout="@layout/include_layout"/>
</LinearLayout>

顯示的效果為:

a.png

  看上去效果非常不錯(cuò)對嗎? 可是在你毫無察覺的情況下,目前activity_main.xml這個(gè)界面當(dāng)中其實(shí)已經(jīng)存在著多余的布局嵌套了肴掷!感覺還沒寫幾行代碼呢敬锐,怎么這就已經(jīng)有多余的布局嵌套了?不信的話我們可以通過UI Automator Viewer工具來查看一下呆瞻,如下圖所示:
include.PNG

  可以看到台夺,最外層首先是一個(gè)FrameLayout,至于為什么是FrameLayout痴脾,不知道的朋友可以去參考 Android LayoutInflater原理分析颤介,帶你一步步深入了解View(一) 這篇文章。然后FrameLayout中包含的是一個(gè)LinearLayout赞赖,這個(gè)就是我們在activity_main.xml中定義的最外層布局了滚朵。

二、merge

通過上面內(nèi)容前域,相信大家已經(jīng)可以看出來了吧辕近,在使用<include/>直接引入布局的時(shí)候,這個(gè)內(nèi)部的LinearLayout其實(shí)就是一個(gè)多余的布局嵌套匿垄,實(shí)際上并不需要這樣一層移宅,讓兩個(gè)按鈕直接包含在外部的LinearLayout當(dāng)中就可以了归粉。而這個(gè)多余的布局嵌套其實(shí)就是由于布局引入所導(dǎo)致的,因?yàn)槲覀冊?strong>include_layout.xml中也定義了一個(gè)LinearLayout漏峰。那么應(yīng)該怎樣優(yōu)化掉這個(gè)問題呢糠悼?請接著往下看當(dāng)然就是使用<merge/>標(biāo)簽了,現(xiàn)在修改include_layout.xml布局如下:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button One"
        android:id="@+id/button" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button Two"
        android:id="@+id/button2" />
</merge>

可以看到浅乔,這里我們將include_layout.xml最外層的LinearLayout布局刪除掉绢掰,換用了<merge/>標(biāo)簽,這就表示當(dāng)有任何一個(gè)地方去include這個(gè)布局時(shí)童擎,會將<merge/>標(biāo)簽內(nèi)包含的內(nèi)容直接填充到include的位置滴劲,不會再添加任何額外的布局結(jié)構(gòu)。好的顾复,<merge/>的用法就是這么簡單班挖,現(xiàn)在重新運(yùn)行一下程序,你會看到界面沒有任何改變芯砸,然后我們再通過UI Automator Viewer工具來查看一下當(dāng)前的View結(jié)構(gòu)萧芙,如下圖所示:

merge.PNG

  好了,可以看到假丧,現(xiàn)在兩個(gè)按鈕都直接包含在了LinearLayout下面双揪,我們的include_layout.xml當(dāng)中也就不存在多余的布局嵌套了。

三包帚、ViewStub

對于ViewStub(請自備梯子)可以理解為僅在需要時(shí)才加載布局渔期。
  ViewStub是一個(gè)輕量級的View,它一個(gè)看不見的渴邦,不占布局位置疯趟,占用資源非常小的控件∧彼螅可以為ViewStub指定一個(gè)布局信峻,在Inflate布局的時(shí)候,只有ViewStub會被初始化瓮床,然后當(dāng)ViewStub被設(shè)置為可見的時(shí)候盹舞,或是調(diào)用了ViewStub.inflate()的時(shí)候,ViewStub所向的布局就會被Inflate和實(shí)例化隘庄,然后ViewStub的布局屬性都會傳給它所指向的布局踢步。這樣,就可以使用ViewStub來方便的在運(yùn)行時(shí)峭沦,要不要顯示某個(gè)布局贾虽。
  但ViewStub也不是萬能的,下面總結(jié)下ViewStub能做的事兒和什么時(shí)候該用ViewStub吼鱼,什么時(shí)候該用可見性的控制蓬豁。
首先來說說ViewStub的一些特點(diǎn):

  1. ViewStub只能Inflate一次,之后ViewStub對象會被置為空菇肃。按句話說地粪,某個(gè)被ViewStub指定的布局被Inflate后,就不會夠再通過ViewStub來控制它了琐谤。
  2. ViewStub只能用來Inflate一個(gè)布局文件蟆技,而不是某個(gè)具體的View,當(dāng)然也可以把View寫在某個(gè)布局文件中斗忌。

基于以上的特點(diǎn)质礼,那么可以考慮使用ViewStub的情況有:

  1. 在程序的運(yùn)行期間,某個(gè)布局在Inflate后织阳,就不會有變化眶蕉,除非重新啟動。因?yàn)閂iewStub只能Inflate一次唧躲,之后會被置空造挽,所以無法指望后面接著使用ViewStub來控制布局。所以當(dāng)需要在運(yùn)行時(shí)不止一次的顯示和隱藏某個(gè)布局弄痹,那么ViewStub是做不到的饭入。這時(shí)就只能使用View的可見性來控制了。
  2. 想要控制顯示與隱藏的是一個(gè)布局文件肛真,而非某個(gè)View谐丢。因?yàn)樵O(shè)置給ViewStub的只能是某個(gè)布局文件的Id,所以無法讓它來控制某個(gè)View蚓让。

所以庇谆,如果想要控制某個(gè)View(如Button或TextView)的顯示與隱藏,或者想要在運(yùn)行時(shí)不斷的顯示與隱藏某個(gè)布局或View凭疮,只能使用View的可見性來控制饭耳。接下來修改include_layout.xml布局如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button"
        android:onClick="onClick"
        android:id="@+id/button1"/>
    <ViewStub
        android:id="@+id/view_stub"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout="@layout/include_layout"/>
</LinearLayout>

現(xiàn)在看看MainActivity的代碼:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    void onClick(View view){
        ViewStub viewStub= (ViewStub) findViewById(view_stub);
       if (viewStub!=null){
           viewStub.inflate();
       }
    }
}

最后來看看使用ViewStub的效果:

GIF.gif

點(diǎn)擊button就會調(diào)用ViewStub的inflate();方法來加載我們需要的布局
最后使用ViewStub需要注意:

  1. 某些布局屬性要加在ViewStub而不是實(shí)際的布局上面,才會起作用执解,比如上面用的android:layout_margin*系列屬性寞肖,如果加在TextView上面,則不會起作用衰腌,需要放在它的ViewStub上面才會起作用新蟆。而ViewStub的屬性在inflate()后會都傳給相應(yīng)的布局。

附上UI Automator Viewer工具的打開方法:AndroidSDK > tools > uiautomatorviewer.bat

img02.png

  最后右蕊,如果大家想要繼續(xù)學(xué)習(xí)更多關(guān)于性能優(yōu)化的技巧琼稻,可以到這個(gè)網(wǎng)址上閱讀更多內(nèi)容 http://developer.android.com/training/best-performance.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饶囚,一起剝皮案震驚了整個(gè)濱河市帕翻,隨后出現(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)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布撒踪。 她就那樣靜靜地躺著,像睡著了一般大渤。 火紅的嫁衣襯著肌膚如雪制妄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天泵三,我揣著相機(jī)與錄音耕捞,去河邊找鬼。 笑死烫幕,一個(gè)胖子當(dāng)著我的面吹牛俺抽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播较曼,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼磷斧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起弛饭,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤冕末,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后孩哑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體栓霜,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡翠桦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年横蜒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片销凑。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡丛晌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出斗幼,到底是詐尸還是另有隱情澎蛛,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布蜕窿,位于F島的核電站谋逻,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏桐经。R本人自食惡果不足惜毁兆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望阴挣。 院中可真熱鬧气堕,春花似錦、人聲如沸畔咧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽誓沸。三九已至梅桩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拜隧,已是汗流浹背宿百。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留虹蓄,地道東北人犀呼。 一個(gè)月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像薇组,于是被迫代替她去往敵國和親外臂。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350

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