詳細(xì)介紹安卓布局性能優(yōu)化之(include 骗绕、merge、ViewStub)

我們?cè)谌粘i_(kāi)發(fā)中,我們可能會(huì)遇到有很多相似的布局,如果每一個(gè)XML文件都寫(xiě)一次,不說(shuō)麻煩,代碼也顯得冗余,而且可讀性也很差.這時(shí)候就需要include 了,本編文章將會(huì)介紹include贮泞、merge和ViewStub標(biāo)簽的用法供大家學(xué)習(xí)和參考楞慈。

include標(biāo)簽

include標(biāo)簽常用于將布局中的公共部分提取出來(lái)供其他layout共用,以實(shí)現(xiàn)布局模塊化,也是平常我們?cè)O(shè)計(jì)布局時(shí)用的最多的

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="wrap_content"
           android:gravity="center_horizontal"
           android:orientation="vertical"> 
<TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="@string/textview"
        android:textSize="24sp"/> <EditText
        android:id="@+id/editText"
        android:hint="@string/divide"
        android:layout_width="300dp"
        android:layout_height="wrap_content"/> </LinearLayout> 

<?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="wrap_content"
                android:gravity="center_horizontal"
    > <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="TextView_Relative"
        android:textSize="24sp"/> <EditText
        android:id="@+id/editText"
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView"
        android:hint="@string/divide"/> </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/tb_toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="#00f"
    app:theme="@style/AppTheme"
    app:title="這是一個(gè)ToolBar"
    app:titleTextColor="@android:color/white"/>
    

1.2啃擦、Activity的XML布局文件調(diào)用include標(biāo)簽:

<?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"
    android:orientation="vertical">
 <!--測(cè)試layout和<include>都設(shè)置ID的情況-->
<include
        android:id="@+id/tb_toolbar"
        layout="@layout/include_toolbar"/> 
<!--如果只有單個(gè)include 這樣寫(xiě)就可以,加載的布局的子View,直接findViewByID就能找到--> 
   <include layout="@layout/include_text"/> 
   <!--如果有多個(gè)include,需要添加ID屬性--> <include
        android:id="@+id/include_text1"
        layout="@layout/include_text"/> 
<!--這個(gè)layout用RelativeLayout 實(shí)現(xiàn)-->
 <!--如果要使用layout_margin這樣的屬性,要同時(shí)加上layout_w/h屬性,不然沒(méi)反應(yīng)--> <include
        android:id="@+id/include_text2"
        layout="@layout/include_text_relative"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="50dp"/>
         </LinearLayout>

1.3囊蓝、Activity中調(diào)用include標(biāo)簽layout中的子View:

 private void initView() { 
 //如果include布局根容器和include標(biāo)簽中的id設(shè)置的是不同的值,這里獲取的mToolbar值將為null 
 Toolbar mToolbar = (Toolbar) findViewById(R.id.tb_toolbar); setSupportActionBar(mToolbar); 
 //普通include標(biāo)簽用法,直接拿子View屬性實(shí)現(xiàn)
  TextView textView = (TextView) findViewById(R.id.textView); textView.setText("不加ID實(shí)現(xiàn)的include標(biāo)簽"); 
  //多個(gè)include標(biāo)簽用法,添加ID,findViewByID找到layout,再找子控件 
  View view_include = findViewById(R.id.include_text1); TextView view_include_textView = (TextView) view_include.findViewById(R.id.textView); view_include_textView.setText("加了ID實(shí)現(xiàn)的include標(biāo)簽"); 
  //多個(gè)include標(biāo)簽用法,添加ID,findViewByID找到layout,再找子控件
   View view_include_Relative = findViewById(R.id.include_text2); TextView view_textView_relative = (TextView) view_include_Relative.findViewById(R.id.textView); view_textView_relative.setText("加了ID實(shí)現(xiàn)的include標(biāo)簽(RelaviteLayout)"); }

==include使用注意==

  • 一個(gè)xml布局文件有多個(gè)include標(biāo)簽需要設(shè)置ID,才能找到相應(yīng)子View的控件,否則只能找到第一個(gè)include的layout布局,以及該布局的控件
  • include標(biāo)簽如果使用layout_xx屬性,會(huì)覆蓋被include的xml文件根節(jié)點(diǎn)對(duì)應(yīng)的layout_xx屬性,建議在include標(biāo)簽調(diào)用的布局設(shè)置好寬高位置,防止不必要的bug
  • include 添加id,會(huì)覆蓋被include的xml文件根節(jié)點(diǎn)ID,這里建議include和被include覆蓋的xml文件根節(jié)點(diǎn)設(shè)置同名的ID,不然有可能會(huì)報(bào)空指針異常
  • 如果要在include標(biāo)簽下使用RelativeLayout,如layout_margin等其他屬性,記得要同時(shí)設(shè)置layout_width和layout_height,不然其它屬性會(huì)沒(méi)反應(yīng)

merge 標(biāo)簽

merge標(biāo)簽主要用于輔助include標(biāo)簽,在使用include后可能導(dǎo)致布局嵌套過(guò)多,多余的layout節(jié)點(diǎn)或?qū)е陆馕鲎兟?可通過(guò)hierarchy viewer工具查看布局的嵌套情況)

官方文檔說(shuō)明:merge用于消除視圖層次結(jié)構(gòu)中的冗余視圖,例如根布局是Linearlayout,那么我們又include一個(gè)LinerLayout布局就沒(méi)意義了,反而會(huì)減慢UI加載速度

merge 官方文檔

  • merge標(biāo)簽常用場(chǎng)景:

    1.根布局是FrameLayout且不需要設(shè)置background或padding等屬性,可以用merge代替,因?yàn)锳ctivity的ContentView父元素就是FrameLayout,所以可以用merge消除只剩一個(gè)令蛉。
    2.某布局作為子布局被其他布局include時(shí),使用merge當(dāng)作該布局的頂節(jié)點(diǎn),這樣在被引入時(shí)頂結(jié)點(diǎn)會(huì)自動(dòng)被忽略,而將其子節(jié)點(diǎn)全部合并到主布局中聚霜。
    3.自定義View如果繼承LinearLayout(ViewGroup),建議讓自定義View的布局文件根布局設(shè)置成merge,這樣能少一層結(jié)點(diǎn)狡恬。

merge標(biāo)簽使用:

在XML布局文件的根布局如RelativeLayout直接改成merge即可

merge使用注意

1.因?yàn)閙erge標(biāo)簽并不是View,所以在通過(guò)LayoutInflate.inflate()方法渲染的時(shí)候,第二個(gè)參數(shù)必須指定一個(gè)父容器,且第三個(gè)參數(shù)必須為true,也就是必須為merge下的視圖指定一個(gè)父親節(jié)點(diǎn).
2.因?yàn)閙erge不是View,所以對(duì)merge標(biāo)簽設(shè)置的所有屬性都是無(wú)效的.
3.注意如果include的layout用了merge,調(diào)用include的根布局也使用了merge標(biāo)簽,那么就失去布局的屬性了
4.merge標(biāo)簽必須使用在根布局
5.ViewStub標(biāo)簽中的layout布局不能使用merge標(biāo)簽

ViewStub 標(biāo)簽

我們?cè)谧霭沧宽?xiàng)目的時(shí)候,經(jīng)常會(huì)有一個(gè)使用場(chǎng)景:需要在運(yùn)行時(shí)根據(jù)數(shù)據(jù)動(dòng)態(tài)決定顯示或隱藏某個(gè)View和布局蝎宇。
上述場(chǎng)景弟劲,我們通常的解決方案就是:就是把可能用到的View先寫(xiě)在布局里,再初始化其可見(jiàn)性都設(shè)為View.GONE姥芥,然后在代碼中根據(jù)數(shù)據(jù)動(dòng)態(tài)的更改它的可見(jiàn)性兔乞。
雖然這樣的實(shí)現(xiàn),邏輯簡(jiǎn)單而且控制起來(lái)比較靈活凉唐;但是也存在一定的缺點(diǎn)耗費(fèi)資源庸追。
ViewStub 標(biāo)簽最大的優(yōu)點(diǎn)是當(dāng)你需要時(shí)才會(huì)加載,使用它并不會(huì)影響UI初始化時(shí)的性能.各種不常用的布局像進(jìn)度條、顯示錯(cuò)誤消息等可以使用ViewStub標(biāo)簽,以減少內(nèi)存使用量,加快渲染速度.ViewStub是一個(gè)不可見(jiàn)的,實(shí)際上是把寬高設(shè)置為0的View.效果有點(diǎn)類(lèi)似普通的view.setVisible(),但性能體驗(yàn)提高不少
第一次初始化時(shí),初始化的是ViewStub View,當(dāng)我們調(diào)用inflate()或setVisibility()后會(huì)被remove掉,然后在將其中的layout加到當(dāng)前view hierarchy中台囱。

先來(lái)看看布局淡溯,一個(gè)是主布局,里面只定義二個(gè)ViewStub簿训,一個(gè)用來(lái)控制TextView一個(gè)用來(lái)控制ImageView咱娶,另外就是一個(gè)是為顯示文字的做的TextView布局,一個(gè)是為ImageView而做的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:gravity="center_horizontal">
  <ViewStub 
    android:id="@+id/viewstub_demo_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="5dip"
    android:layout_marginRight="5dip"
    android:layout_marginTop="10dip"
    android:layout="@layout/viewstub_demo_text_layout"/>
  <ViewStub 
    android:id="@+id/viewstub_demo_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="5dip"
    android:layout_marginRight="5dip"
    android:layout="@layout/viewstub_demo_image_layout"/>
</LinearLayout>

為T(mén)extView的布局:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="vertical"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content">
        <TextView
            android:id="@+id/viewstub_demo_textview"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="#aa664411"
            android:textSize="16sp"/>
    </LinearLayout>

為ImageView的布局:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="vertical"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content">
        <ImageView
            android:id="@+id/viewstub_demo_imageview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    </LinearLayout>

下面來(lái)看代碼煎楣,決定來(lái)顯示哪一個(gè),只需要找到相應(yīng)的ViewStub然后調(diào)用其infalte()就可以獲得相應(yīng)想要的布局:

    public class ViewStubDemoActivity extends Activity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.viewstub_demo_activity);
            if ((((int) (Math.random() * 100)) & 0x01) == 0) {
                // to show text
                // all you have to do is inflate the ViewStub for textview
                ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_text);
                stub.inflate();
                TextView text = (TextView) findViewById(R.id.viewstub_demo_textview);
                text.setText("The tree of liberty must be refreshed from time to time" +
                        " with the blood of patroits and tyrants! Freedom is nothing but " +
                        "a chance to be better!");
            } else {
                // to show image
                // all you have to do is inflate the ViewStub for imageview
                ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_image);
                stub.inflate();
                ImageView image = (ImageView) findViewById(R.id.viewstub_demo_imageview);
                image.setImageResource(R.drawable.happy_running_dog);
            }
        }
    }

ViewStub標(biāo)簽使用注意

  1. ViewStub標(biāo)簽不支持merge標(biāo)簽
  2. ViewStub的inflate只能被調(diào)用一次,第二次調(diào)用會(huì)拋出異常,setVisibility可以被調(diào)用多次,但不建議這么做(ViewStub 調(diào)用過(guò)后,可能被GC掉,再調(diào)用setVisibility()會(huì)報(bào)異常)
  3. 為ViewStub賦值的android:layout_XX屬性會(huì)替換待加載布局文件的根節(jié)點(diǎn)對(duì)應(yīng)的屬性

擴(kuò)展:

Space組件

在ConstraintLayout出來(lái)前,我們寫(xiě)布局都會(huì)使用到大量的margin或padding,但是這種方式可讀性會(huì)很差,加一個(gè)布局嵌套又會(huì)損耗性能

鑒于這種情況,我們可以使用space,使用方式和View一樣,不過(guò)主要用來(lái)占位置,不會(huì)有任何顯示效果

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末车伞,一起剝皮案震驚了整個(gè)濱河市择懂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌另玖,老刑警劉巖困曙,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異谦去,居然都是意外死亡慷丽,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)鳄哭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)要糊,“玉大人,你說(shuō)我怎么就攤上這事妆丘〕恚” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵勺拣,是天一觀的道長(zhǎng)奶赠。 經(jīng)常有香客問(wèn)我,道長(zhǎng)药有,這世上最難降的妖魔是什么毅戈? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上苇经,老公的妹妹穿的比我還像新娘赘理。我一直安慰自己,他們只是感情好塑陵,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布感憾。 她就那樣靜靜地躺著,像睡著了一般令花。 火紅的嫁衣襯著肌膚如雪阻桅。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,784評(píng)論 1 290
  • 那天兼都,我揣著相機(jī)與錄音嫂沉,去河邊找鬼。 笑死扮碧,一個(gè)胖子當(dāng)著我的面吹牛趟章,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播慎王,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蚓土,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了赖淤?” 一聲冷哼從身側(cè)響起蜀漆,我...
    開(kāi)封第一講書(shū)人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎咱旱,沒(méi)想到半個(gè)月后确丢,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吐限,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年鲜侥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诸典。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡描函,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出狐粱,到底是詐尸還是另有隱情赘阀,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布脑奠,位于F島的核電站基公,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏宋欺。R本人自食惡果不足惜轰豆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一胰伍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酸休,春花似錦骂租、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至宿刮,卻和暖如春互站,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背僵缺。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工胡桃, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人磕潮。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓翠胰,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親自脯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子之景,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

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