Android 從源碼角度理解LayoutInflater的解析過程

在Android開發(fā)中咆槽,我們通過LayoutInflater去解析布局文件生成對應(yīng)的View對象收擦。

方法參數(shù):

public View inflate(int resource, ViewGroup root, boolean attachToRoot) {

由于傳入的方法參數(shù)不同哆键,該方法返回的view也會不同苞轿,接下來通過查看源碼嗜傅,來探究其處理邏輯金句。

為了讓代碼篇幅短一些,我省掉了一些不影響邏輯的代碼吕嘀,在重要的地方加了注釋违寞,其他代碼邏輯讀者可以查看源碼。

 public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
        final Resources res = getContext().getResources();
       ...
        //通過傳入的布局資源文件獲取xml資源解析對象
        final XmlResourceParser parser = res.getLayout(resource);
        try {
            return inflate(parser, root, attachToRoot);
        } finally {
            parser.close();
        }
    }

inflate內(nèi)部調(diào)用了inflate(parser, root, attachToRoot)偶房;該方法實現(xiàn)了解析布局文件趁曼。

 public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
        synchronized (mConstructorArgs) {
            final AttributeSet attrs = Xml.asAttributeSet(parser);
            ...
            View result = root;

            // Temp is the root view that was found in the xml
           //這里獲取的是資源文件根布局的對象
            final View temp = createViewFromTag(root, name, attrs, false);

            ViewGroup.LayoutParams params = null;

            if (root != null) {
                if (DEBUG) {
                    System.out.println("Creating params from root: " +
                            root);
                }
                // Create layout params that match root, if supplied
                //獲取根布局的Layoutparams屬性
                params = root.generateLayoutParams(attrs);
                if (!attachToRoot) {
                    // Set the layout params for temp if we are not
                    // attaching. (If we are, we use addView, below)
                    //給布局資源根對象設(shè)置布局文件最外層layout屬性
                    temp.setLayoutParams(params);
                }
            }
                    ...
            // Inflate all children under temp
            rInflate(parser, temp, attrs, true, true);
                    ..
            // We are supposed to attach all the views we found (int temp)
            // to root. Do that now.
            if (root != null && attachToRoot) {
                //將布局文件加入root中
                root.addView(temp, params);
            }

            // Decide whether to return the root that was passed in or the
            // top view found in xml.
            if (root == null || !attachToRoot) {
                result = temp;
            }
        }
        
        return result;
    }
               

通過布局文件的屬性集attrs,來獲取資源布局文件最外層的LayoutParams的屬性

 params = root.generateLayoutParams(attrs);

他的內(nèi)部實現(xiàn)為:

public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LayoutParams(getContext(), attrs);
    }

 public LayoutParams(Context c, AttributeSet attrs) {
            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
            setBaseAttributes(a,
                    R.styleable.ViewGroup_Layout_layout_width,
                    R.styleable.ViewGroup_Layout_layout_height);
            a.recycle();
        }

這里需要說明一點棕洋,root的變量定義為ViewGroup挡闰,viewGroup的generateLayoutParams內(nèi)部執(zhí)行是生成LayoutParams,它內(nèi)部會去獲取layout_width與layout_height掰盘。

讓我們試著看下LinearLayout的generateLayoutParams()實現(xiàn)方式摄悯。

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LinearLayout.LayoutParams(getContext(), attrs);
    }
   public LayoutParams(Context c, AttributeSet attrs) {
        super(c, attrs);
         TypedArray a = c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout);
         weight = a.getFloat(com.android.internal.R.styleable.LinearLayout_Layout_layout_weight, 0);
         gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -1);
         a.recycle();
        }

可以發(fā)現(xiàn)在LinearLayout中不僅獲取了layot_width和layout_height,還獲取了weight和gravity愧捕。

通過源碼的實現(xiàn)邏輯奢驯,可以總結(jié)如下:

  1. root不為空時,attchToRoot為true時次绘,執(zhí)行
final View temp = createViewFromTag(root, name, attrs, false);
params = root.generateLayoutParams(attrs);
root.addView(temp, params);

這時解析的布局文件view對象會成為root的子View瘪阁;

2.root不為空,attchToRoot為false邮偎,執(zhí)行

 final View temp = createViewFromTag(root, name, attrs, false);
 params = root.generateLayoutParams(attrs);
 temp.setLayoutParams(params);
 result = temp;
 return result;

這里面將布局文件最外層的layout布局參數(shù)管跺,設(shè)置給了布局文件View的LayoutParams字段。

3.root為空時,執(zhí)行

 final View temp = createViewFromTag(root, name, attrs, false);
 result = temp;
 return result;

這種解析出來的View對象是LayoutParams屬性字段為空钢猛,在調(diào)用addView()方法時伙菜,Android系統(tǒng)會默認(rèn)生成一個寬高均為wrap_content屬性的LayoutParams。

總結(jié):之所以這樣寫命迈,是建立在一個很重要的原因上贩绕,那就是layout_width這個表示的是View 在布局中的寬度 火的。對與LayoutInfalter來說,去解析一個布局文件淑倾,如果你不將該view加入ViewGroup中去的馏鹤,就沒必要獲取這個view“在布局中的屬性了”,

在使用View temp = createViewFromTag(root, name, attrs, false);去獲取View時娇哆,得到的View對象是沒有 布局屬性的湃累,所以才有了LayoutInfalter該方法。

view的屬性字段中有 protected ViewGroup.LayoutParams mLayoutParams;
temp.setLayoutParams(params);該方法給布局根View設(shè)置了“在布局中的屬性”

另外generateLayoutParams(attrs);不同ViewGroup的該方法實現(xiàn)過程不同碍讨,但是她們都沒有獲取根布局的 layout_margin屬性治力,這也就解釋了我們ListView的item布局文件中最外層節(jié)點設(shè)置了layout_margin屬性失效的原因了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末勃黍,一起剝皮案震驚了整個濱河市宵统,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌覆获,老刑警劉巖马澈,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異弄息,居然都是意外死亡痊班,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門摹量,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涤伐,“玉大人,你說我怎么就攤上這事荆永》贤ぃ” “怎么了国章?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵具钥,是天一觀的道長。 經(jīng)常有香客問我液兽,道長骂删,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任四啰,我火速辦了婚禮宁玫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘柑晒。我一直安慰自己欧瘪,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布匙赞。 她就那樣靜靜地躺著佛掖,像睡著了一般妖碉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上芥被,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天欧宜,我揣著相機(jī)與錄音,去河邊找鬼拴魄。 笑死冗茸,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的匹中。 我是一名探鬼主播夏漱,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼顶捷!你這毒婦竟也來了麻蹋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤焊切,失蹤者是張志新(化名)和其女友劉穎扮授,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體专肪,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡刹勃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了嚎尤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荔仁。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖芽死,靈堂內(nèi)的尸體忽然破棺而出乏梁,到底是詐尸還是另有隱情,我是刑警寧澤关贵,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布遇骑,位于F島的核電站,受9級特大地震影響揖曾,放射性物質(zhì)發(fā)生泄漏落萎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一炭剪、第九天 我趴在偏房一處隱蔽的房頂上張望练链。 院中可真熱鬧,春花似錦奴拦、人聲如沸媒鼓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绿鸣。三九已至瓷产,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間枚驻,已是汗流浹背濒旦。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留再登,地道東北人尔邓。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像锉矢,于是被迫代替她去往敵國和親梯嗽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

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