Android 你的自定義View是否比別人多了一個層級

前言

最近部門內對View的加載做了一波優化操作,主要是針對一些在特定時機才會顯示在頁面上的View進行ViewStub化改造。優化后,頁面的啟動速度確實得到了提升。這確實是一個項目優化的入手點。在做完這波優化后,我偶然間腦海中閃過一個念頭,就是我們項目中的自定義View的層級是否存在可改進的地方,于是我在閑暇之余自己寫了個小demo,并閱讀了下LayoutInflater的一些源碼,發現果然我們項目中的大部分組合自定義View都存在一層多余的層級。

“多一層外套”的組合自定義View

組合自定義View在日常開發中的引用場景應該還是相對比較多的,下面我粘上一個簡單的組合自定義View的實現:

/**
 * 簡單的一個組合自定義View,在它的中央會顯示一個TextView文本
 * 此案例的布局填充方式也是目前網上包括一些書籍描述的填充方式
 */
public class GroupNormalView extends RelativeLayout {
    
    public GroupNormalView(Context context) {
        this(context, null);
    }

    public GroupNormalView(Context context, AttributeSet attrs) {
        super(context, attrs);
        LayoutInflater.from(context).inflate(R.layout.group_normal_view, this, true);
    }
}

xml布局:

<?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">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textSize="25sp"
        android:textColor="#ff0000"
        android:text="Normal" />
</RelativeLayout>

然后,我在MainActivity的布局中引入這個自定義View。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context="activity.MainActivity">

    <view.GroupNormalView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

運行demo,當頁面打開后,我們使用AS自帶的Layout Inspector工具來查看當前頁面的布局組成。如下圖:


normal.png

當前頁面的布局內容中僅含一個GroupNormalView,在它的里面包含一層相對布局,然后還有一個TextView。看最初定義GroupNormalView的時候我直接讓它繼承了RelativeLayout,也就是說GroupNormalView本身就含有RelativeLayout的全部布局屬性了,那么現在有沒有覺著上圖中第二個箭頭所指的RelativeLayout有些多余呢?事實證明,真的很多余。下面就讓我們把這多余的一層布局給干掉。

“比基尼裝扮”的組合自定義View

其實,干掉上面所說的那一層多余的布局的方式有兩種。一種是在自定義控件的xml文件中,直接把布局根標簽改成merge。但是這種方式有一個缺點,就是在開發過程中我們無法實時的在右側preview中瀏覽到正確的布局排列樣式。因此我更傾向于接下來要說的這種方式,就是直接在布局文件中引用自定義View。
代碼實現:

/**
 * 組合自定義View,View直接在xml布局中被引用。如需遍歷布局中的控件,可重寫onFinishInflate方法
 */
public class GroupBetterView extends RelativeLayout {
    
    private TextView betterTxt;
    
    public GroupBetterView(Context context) {
        super(context);
    }

    public GroupBetterView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        betterTxt = findViewById(R.id.txt_better);
    }
}

xml布局(group_better_view):

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

    <TextView
        android:id="@+id/txt_better"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textSize="25sp"
        android:textColor="#ff0000"
        android:text="Better" />
</view.GroupBetterView>

然后,在MainActivity的布局中使用include標簽引入自定義控件的布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context="activity.MainActivity">
    
    <include layout="@layout/group_better_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

同樣,運行demo,打開Layout Inspector工具,結果如下圖:


better.png

看到了吧,實現了一模一樣的效果,但是現在比之前少了一層相對布局。我們都知道,在View的繪制過程中,多一層布局的話它的繪制時間肯定就更長。試想下,如果一個頁面存在上千個View的話,如果我們采用第一種方式實現,無非是會增加頁面整體的繪制時間的。因此以后再使用組合自定義View的時候,要優先選擇第二種方式啊。

關于inflate()方法:

現在,我們只是從結果上證實了,確實第二種方式減少了一層層級,但是我們還不知道為什么會是這樣子呢。下面,我們就再來看下LayoutInflater的源碼吧。點進inflate方法,一路行走至483行:


mergeinflate.png

我們可以看到,如果發現xml布局中根標簽的名字為merge的話,會進入if條件中,而不是merge的話會進入else中,而第一種方式我們布局中的根標簽為RelativeLayout,因此我們繼續看else中的代碼,第492行,在這里創建了一個temp對象,上面的注釋寫的很清楚,這個對象就是在xml布局中的根View。然后繼續往下走,至524行如下:


addview.png

看到了吧,當root(也就是當前自定義View)不為空,并且attachRoot(我們在調用inflate方法時傳入的第三個參數)為true時,是將xml中的根View當做一個子View添加進了自定義View中,這下知道為什么第一種方式比第二種方式多了一層布局了吧!

總結

本文算是一個自定義View上使用的一個小優化,希望能夠對大家有所幫助。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內容

  • 【Android 自定義View】 [TOC] 自定義View基礎 接觸到一個類,你不太了解他,如果貿然翻閱源碼只...
    Rtia閱讀 3,968評論 1 14
  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,149評論 4 61
  • 看完阿黛爾的生活,我哭濕了枕頭。迷茫成長.不說題材,而說看到兩個吵架被絕情的趕出來,沒有追和彌補,然后三年過去,阿...
    燕coco閱讀 1,004評論 0 5
  • 想起曾經的初中同學z,z的父母在她從小就離異了,把她留給了父親,因為父親愧對于沒有給她個完美的家庭,所以對她萬千寵...
    蘭漠子閱讀 222評論 0 0
  • 發心:我今不是為了我個人而聞思修,而是為了六道輪回一切如母有情眾生,愿一切如母有情眾生能夠早日離苦得樂,清凈業障,...
    曉茂閱讀 200評論 5 7