性能優(yōu)化(1.2)-布局優(yōu)化(扁平化颜曾,Merge的使用瘾境,ViewStub的使用)

主目錄見:Android高級進(jìn)階知識(這是總目錄索引)
?今天之所以講這一篇主要是為了下一篇[APP啟動速度優(yōu)化實例解析]做鋪墊的,我們都知道我們解決UI卡頓問題中主要就是:

  1. 優(yōu)化CPU的計算時間或者不必要的布局導(dǎo)致測量布局時間變長;
  2. 優(yōu)化GPU的過度繪制祸轮,主要方法可以在手機(jī)打開GPU檢測或者在Android studio中的Hierarchy Viewer可以查看層級。

針對這兩種情況一般會有下面的因素或者處理方式可以優(yōu)化:

  • 在拼接字符串時候盡量使用StringBuilder避免大量的GC導(dǎo)致卡頓侥钳;
  • 避免在主線程做大量的計算任務(wù)适袜,比如遞歸的操作導(dǎo)致CPU時間占用長導(dǎo)致卡頓;
  • 去掉window的背景舷夺,因為DecorView默認(rèn)會有一個純色的背景苦酱,在我們布局設(shè)置了背景的話,那么這個背景對我們來說是多余的给猾;
  • 去掉不必要的背景疫萤,因為在我們布局有嵌套的情況下,如果都設(shè)置了背景的話有可能存在不必要的背景導(dǎo)致重繪耙册;
  • 利用clipRect的方式來減少繪制層數(shù),一個典型的例子就是撲克牌重疊導(dǎo)致重繪毫捣;
  • 利用include详拙,merge,ViewStub等標(biāo)簽來減少嵌套層數(shù)蔓同。

今天我們就是主要來講的最后一種方法的使用饶辙,這個方式應(yīng)該說能很有效解決過渡繪制的問題。

一.目標(biāo)

我們今天的目標(biāo)也是很簡單的斑粱,就是看這幾個標(biāo)簽是怎么使用的弃揽,然后能在實際應(yīng)用中使用到,所以今天目標(biāo):
1.學(xué)會include则北,merge矿微,ViewStub這三個標(biāo)簽怎么使用;
2.明白什么情況下使用哪個標(biāo)簽以及用這三個標(biāo)簽來優(yōu)化尚揣。

二.標(biāo)簽使用

1.<include/>重用布局

首先我們第一個來講講<include/>的使用涌矢,若幾個布局界面存在較多的共同模塊,可以進(jìn)行代碼塊的重用,編寫進(jìn)入一個共同的布局里面,然后在多個布局文件中使用include標(biāo)簽進(jìn)行引入。這里我們舉個例子比如頂部欄:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="50dp">
    <Button
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:background="@mipmap/back_arrow"
        android:layout_gravity="center"
        android:layout_marginLeft="10dp"
        />

    <TextView
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="標(biāo)題"
        android:textColor="@color/colorPrimary"
        android:textSize="20sp"
        android:gravity="center"/>

    <Button
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:background="@mipmap/btn_search"
        android:layout_gravity="center"/>
</LinearLayout>

這里只是簡單布局了下快骗,大家湊合著看哈娜庇,效果圖如下:

頂部欄

那么如果我們的項目中會使用多次這個頂部欄的話(當(dāng)然增加頂部欄不會每個頁面include),那么我們這時候就可以用include:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
   <include layout="@layout/layout"/>
</LinearLayout>

這樣我們就可以把公共的布局抽出來當(dāng)做獨立的部分了方篮,這個標(biāo)簽應(yīng)該來說用的還是比較多的名秀。

2.<merge/>減少布局層數(shù)

我們知道我們布局解析的時候是一層一層遞歸調(diào)用rinflate,然后再回歸講view添加到父視圖中去藕溅,最后整個視圖才創(chuàng)建完畢匕得。如果嵌套層數(shù)太多的話,就會導(dǎo)致這個解析的過程任務(wù)量變大從而導(dǎo)致解析速度變慢巾表,這樣的話我們可以用<merge/>標(biāo)簽來進(jìn)行優(yōu)化耗跛。我們首先來用androidstudio中的Hierarchy Viewer來查看我們剛才布局的層級:

Hierarchy Viewer查看布局

可以看到我們布局是從最上面的contentFrameLayout往下的裕照,為什么呢?因為我們看setContentView源碼的時候我們知道调塌,我們的布局是在id為content的FrameLayout下面晋南,如果不知道可以參考setContentView源碼分析這篇文章,然后我們看到往下的話還有兩層的LinearLayout布局羔砾,很明顯负间,有一層LinearLayout是沒有用的。所以我們來優(yōu)化一下:

<?xml version="1.0" encoding="utf-8"?>
<merge
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
   <include layout="@layout/layout"/>
</merge>

我們看到姜凄,這樣的話就少了一層LinearLayout政溃,也可以把里面的LinearLayout去掉,但是這樣的布局就要又外層的布局來決定了:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="50dp">
    <Button
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:background="@mipmap/back_arrow"
        android:layout_gravity="center"
        android:layout_marginLeft="10dp"
        />

    <TextView
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="標(biāo)題"
        android:textColor="@color/colorPrimary"
        android:textSize="20sp"
        android:gravity="center"/>

    <Button
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:background="@mipmap/btn_search"
        android:layout_gravity="center"/>
</merge>

那么我們外層的布局就要改成:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:orientation="horizontal"
    >
   <include layout="@layout/layout"/>
</LinearLayout>

好啦态秧,到這里我們這個標(biāo)簽已經(jīng)講完了董虱,這個標(biāo)簽的功能主要就是為了減少層數(shù)的。

3.<ViewStub/>延遲加載布局

其實ViewStub就是一個寬高都為0的一個View申鱼,它默認(rèn)是不可見的愤诱,只有通過調(diào)用setVisibility函數(shù)或者Inflate函數(shù)才 會將其要裝載的目標(biāo)布局給加載出來,從而達(dá)到延遲加載的效果捐友,這個要被加載的布局通過android:layout屬性來設(shè)置淫半。例如我們通過一個 ViewStub來惰性加載一個消息流的評論列表,因為一個帖子可能并沒有評論匣砖,此時我可以不加載這個評論的ListView科吭,只有當(dāng)有評論時我才把它加 載出來,這樣就去除了加載ListView帶來的資源消耗以及延時:

<?xml version="1.0" encoding="utf-8"?>
<merge
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
   <include layout="@layout/layout"/>

   <ViewStub
       android:inflatedId="@+id/network_error_id"
       android:layout="@layout/network_error"
       android:id="@+id/network_error"
       android:layout_width="match_parent"
       android:layout_height="match_parent"/>
</merge>

這里的inflatedId指的是layout/network_error的跟id猴鲫,android:layout指的是布局network_error的布局对人。然后我們要讓他顯示出來:

    if (null == netWorkError){
            ViewStub netWorkErrorStub = (ViewStub)findViewById(R.id.network_error);
            netWorkError = netWorkErrorStub.inflate();
        }else{
            netWorkError.setVisibility(View.VISIBLE);
        }

ViewStub標(biāo)簽和GONE都是會使一個視圖不可見,但是設(shè)置為GONE的話在渲染的時候還是會被添加到視圖樹里面拂共,而ViewStub只有在inflate之后才會被添加到視圖樹上面规伐,所以減少了一次性渲染的壓力。
注意事項

  • 判斷是否已經(jīng)加載過匣缘, 如果通過setVisibility來加載猖闪,那么通過判斷可見性即可;如果通過inflate()來加載是不可以通過判斷可見性來處理的肌厨,所以需要判斷加載的視圖是否為空來判斷培慌。
  • findViewById的問題,注意ViewStub中是否設(shè)置了inflatedId柑爸,如果設(shè)置了則需要通過inflatedId來查找目標(biāo)布局的根元素吵护。
  • ViewStub不能與merge一起聯(lián)合使用。

總結(jié):今天我們講了這三個標(biāo)簽,應(yīng)該說是開發(fā)過程中用的比較頻繁的馅而,希望大家如果又遇到布局優(yōu)化問題能想到用這個來解決祥诽,當(dāng)然,今天只是講了一小部分的內(nèi)容瓮恭,優(yōu)化的內(nèi)容還是很多的雄坪,希望我們一起努力。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末屯蹦,一起剝皮案震驚了整個濱河市维哈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌登澜,老刑警劉巖阔挠,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異脑蠕,居然都是意外死亡购撼,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進(jìn)店門谴仙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來迂求,“玉大人,你說我怎么就攤上這事狞甚∷ぃ” “怎么了廓旬?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵哼审,是天一觀的道長。 經(jīng)常有香客問我孕豹,道長涩盾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任励背,我火速辦了婚禮春霍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘叶眉。我一直安慰自己址儒,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布衅疙。 她就那樣靜靜地躺著莲趣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪饱溢。 梳的紋絲不亂的頭發(fā)上喧伞,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼潘鲫。 笑死翁逞,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的溉仑。 我是一名探鬼主播挖函,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼彼念!你這毒婦竟也來了挪圾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤逐沙,失蹤者是張志新(化名)和其女友劉穎哲思,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吩案,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡棚赔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了徘郭。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片靠益。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖残揉,靈堂內(nèi)的尸體忽然破棺而出胧后,到底是詐尸還是另有隱情,我是刑警寧澤抱环,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布壳快,位于F島的核電站,受9級特大地震影響镇草,放射性物質(zhì)發(fā)生泄漏眶痰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一梯啤、第九天 我趴在偏房一處隱蔽的房頂上張望竖伯。 院中可真熱鬧,春花似錦因宇、人聲如沸七婴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽打厘。三九已至,卻和暖如春杭棵,著一層夾襖步出監(jiān)牢的瞬間婚惫,已是汗流浹背氛赐。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留先舷,地道東北人艰管。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像蒋川,于是被迫代替她去往敵國和親牲芋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,047評論 2 355

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