Activity的setContentView的流程

上一篇說了Activity和Window關(guān)聯(lián)源碼分析祈惶,現(xiàn)順著源碼查看下Activity的setContentView的具體原理官地,了解為什么我們在Activity的布局的添加流程挫掏。
Activity的setContentView()方法瘦陈,源碼如下:

    public void setContentView(int layoutResID) {
        getWindow().setContentView(layoutResID);
    }

本質(zhì)是調(diào)用的Activity內(nèi)部的window的setContentView()方法鳖谈,上面文章了解到岁疼,Activity內(nèi)部的mWindow對象,實際是一個PhoneWindow實例缆娃,所以activity的setContentView方法捷绒,就是調(diào)用了PhoneWindow內(nèi)部的setContentView(),PhoneWindow內(nèi)部方法如下:

public class PhoneWindow extends Window implements MenuBuilder.Callback {
    ...... 
    @Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
        mLayoutInflater.inflate(layoutResID, mContentParent);
        final Callback cb = getCallback();
        if (cb != null) {
            cb.onContentChanged();
        }
    }
    ......
    private void installDecor() {
        if (mDecor == null) {
            mDecor = generateDecor();
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);

            mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
            if (mTitleView != null) {
                if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
                    View titleContainer = findViewById(com.android.internal.R.id.title_container);
                    if (titleContainer != null) {
                        titleContainer.setVisibility(View.GONE);
                    } else {
                        mTitleView.setVisibility(View.GONE);
                    }
                    if (mContentParent instanceof FrameLayout) {
                        ((FrameLayout)mContentParent).setForeground(null);
                    }
                } else {
                    mTitleView.setText(mTitle);
                }
            }
        }
    }
    ......
}

方法中的贯要,mContentParent暖侨,就是我們?nèi)粘V赖腶ndroid:id/content的布局,而我們?nèi)粘5膕etContentView的這個view或者是layout崇渗,父布局就是此處的mContentParent字逗。順著源碼看京郑,首先判斷mContentParent是否為空,初次調(diào)用葫掉,此處為空些举,進入installDecor()方法。
installDecor()方法挖息,首先判斷了mDecor金拒,這個mDecor是PhoneWindow的一個內(nèi)部類DecorView的實例,是一個FrameLayout套腹,acitivty對應(yīng)的布局界面的最頂層的視圖绪抛。首先判空處理,為空則調(diào)用generateDecor()方法生成一個對象电禀。

    protected DecorView generateDecor() {
        return new DecorView(getContext(), -1);
    }

接下來是判斷mContentParent幢码,若為null,則調(diào)用generateLayout()方法生成mContentParent尖飞,方法源碼如下

  protected ViewGroup generateLayout(DecorView decor) {
        // Apply data from current theme.
        TypedArray a = getWindowStyle();
        ......
        mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);
        int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
                & (~getForcedWindowFlags());
        
        ......
        if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {//布局設(shè)置左右圖標
            if (mIsFloating) {
                layoutResource = com.android.internal.R.layout.dialog_title_icons;
            } else {
                layoutResource = com.android.internal.R.layout.screen_title_icons;
            }
            // System.out.println("Title Icons!");
        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0) {//布局增加進度條
            // Special case for a window with only a progress bar (and title).
            // XXX Need to have a no-title version of embedded windows.
            layoutResource = com.android.internal.R.layout.screen_progress;
            // System.out.println("Progress!");
        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {//自定義title
            // Special case for a window with a custom title.
            // If the window is floating, we need a dialog layout
            if (mIsFloating) {
                layoutResource = com.android.internal.R.layout.dialog_custom_title;
            } else {
                layoutResource = com.android.internal.R.layout.screen_custom_title;
            }
        } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {//默認情況
            // If no other features and not embedded, only need a title.
            // If the window is floating, we need a dialog layout
            if (mIsFloating) {
                layoutResource = com.android.internal.R.layout.dialog_title;
            } else {
                layoutResource = com.android.internal.R.layout.screen_title;
            }
            // System.out.println("Title!");
        } else {//notitle的情形
            // Embedded, so no decoration is needed.
            layoutResource = com.android.internal.R.layout.screen_simple;
            // System.out.println("Simple!");
        }

        mDecor.startChanging();

        View in = mLayoutInflater.inflate(layoutResource, null);
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));

        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        if (contentParent == null) {
            throw new RuntimeException("Window couldn't find content container view");
        }
        ......
        return contentParent;
    }

根據(jù)設(shè)置的window屬性(feature和windowStyle)症副,做不同處理。默認情況下政基,features為DEFAULT_FEATURES贞铣,它的詳細定義在Window內(nèi)部,可自行查看沮明。根據(jù)不同的features辕坝,添加不同的布局,默認布局為R.layout.screen_title荐健,調(diào)用PhoneWindow的成員變量mLayoutInflater酱畅,加載布局文件并添加到根視圖mDecor中;而mContentParent江场,則是mDecor內(nèi)部的一個id為ID_ANDROID_CONTENT的viewGroup纺酸。
回到installDecor()方法中,獲取mContentParent后址否,設(shè)置title相關(guān)內(nèi)容餐蔬。如果設(shè)置的features不是FEATURE_NO_TITLE,則表示有title佑附,便會去設(shè)置title樊诺。同時根據(jù)上述代碼,可以知道帮匾,為什么activity內(nèi)部調(diào)用requestWindowFeature設(shè)置窗口屬性啄骇,需要放在setContentView前面才可以,它本質(zhì)是就是通過PhoneWindow的requestFeature()方法去實現(xiàn)的。
回到PhoneWindow的setContentView方法瘟斜,調(diào)用了installDecor()方法缸夹,可以獲取mContentParent痪寻,然后將布局或視圖加載到當前的mContentParent中(通過LayoutInflater.inflate或者是addView去實現(xiàn)),最終虽惭,布局設(shè)置完成橡类,回調(diào)當前Window.Callback對象的onContentChanged(),返回給Activity芽唇,剩下的由用戶自行處理顾画。

    ......
        final Callback cb = getCallback();
        if (cb != null) {
            cb.onContentChanged();
        }
    ......

所以,我們現(xiàn)在知道了匆笤,acitivity內(nèi)部維持了一個Window對象研侣,實際是PhoneWindow實例,而activity的布局視圖炮捧,就是放在PhoneWindow內(nèi)部的一個mDecor布局中庶诡,而 我們的布局,其實是放在了mDecor內(nèi)部的一個content的FrameLayout里面咆课。

Paste_Image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末末誓,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子书蚪,更是在濱河造成了極大的恐慌喇澡,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件殊校,死亡現(xiàn)場離奇詭異晴玖,居然都是意外死亡,警方通過查閱死者的電腦和手機箩艺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門窜醉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宪萄,“玉大人艺谆,你說我怎么就攤上這事“萦ⅲ” “怎么了静汤?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長居凶。 經(jīng)常有香客問我虫给,道長,這世上最難降的妖魔是什么侠碧? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任抹估,我火速辦了婚禮,結(jié)果婚禮上弄兜,老公的妹妹穿的比我還像新娘药蜻。我一直安慰自己瓷式,他們只是感情好,可當我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布语泽。 她就那樣靜靜地躺著贸典,像睡著了一般。 火紅的嫁衣襯著肌膚如雪踱卵。 梳的紋絲不亂的頭發(fā)上廊驼,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天,我揣著相機與錄音惋砂,去河邊找鬼妒挎。 笑死,一個胖子當著我的面吹牛西饵,可吹牛的內(nèi)容都是我干的饥漫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼罗标,長吁一口氣:“原來是場噩夢啊……” “哼庸队!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起闯割,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤彻消,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后宙拉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體津畸,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年著恩,在試婚紗的時候發(fā)現(xiàn)自己被綠了粗俱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡锥忿,死狀恐怖牛郑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情敬鬓,我是刑警寧澤淹朋,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站钉答,受9級特大地震影響础芍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜数尿,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一仑性、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧右蹦,春花似錦诊杆、人聲如沸鲫懒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窥岩。三九已至,卻和暖如春宰缤,著一層夾襖步出監(jiān)牢的瞬間颂翼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工慨灭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留朦乏,地道東北人。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓氧骤,卻偏偏與公主長得像呻疹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子筹陵,可洞房花燭夜當晚...
    茶點故事閱讀 45,455評論 2 359

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