setContentView()源碼的理解

setContentView()源碼的理解

通俗的解釋

使用場景

在Activity中的onCreate()方法中,我們會使用setContentView()給Activity加載佈局。但實際情況卻不是我們通常使用時理解的那樣。正如setContentView()方法名那樣,是將layout設置給content,而不是設置給Activity。

先放結論

Activity的佈局是有特定的模板,我們通常只是給Content區域填充View
以screen_custom_title.xml模板爲例(查看源碼請按這裏),會得到下圖

這裏寫圖片描述
簡單梳理一下執行流程:

Created with Raphaël 2.1.0setContentView(layout)初始化DecorView(FrameLayout)根據情況初始化相應的ViewGroup將ViewGroup添加到DecorView中在ViewGroup中找到Content(FrameLayout)對象將Layout填充到Content中其他操作

以findViewById()爲例,來進一步理解

在Activity中,我們使用findViewById()都很熟練,感覺沒什麼特別的。但是在Framework中,想要找到特定的控件對象,會使用

view.findViewById(id);

來獲取相應的控件。實際上,findViewById()是View當中的方法在Activity中,findViewById()實際上是調用DecorView.findViewById(),只是不給使用者展示。也就是說,DecorView是外層的佈局,也從側面驗證了上圖。

RTFSC解釋

爲了把握整體思路,這裏並沒有詳細地說明每一行代碼

Activity中的相關代碼

public void setContentView(@LayoutRes int layoutResID) {
    //會調用PhoneWindow中的代碼
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

PhoneWindow中setContentView()相關代碼

public void setContentView(int layoutResID) {
    //mContentParent,也就是Content(上圖淺紫色,與Title平級的部分)
    if (mContentParent == null) {
        //DecorView會在這裏初始化,ViewGroup也在該方法中添加到DecorView中了,同時找打了mContentParent對象
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }

    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                getContext());
        transitionTo(newScene);
    } else {
        //將我們的Layout填充到mContentParent中
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
}

installDecor()中相關的代碼,有省略代碼

private void installDecor() {
    if (mDecor == null) {
        //初始化DecorView
        mDecor = generateDecor();
        //一些相關的配置
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        mDecor.setIsRootNamespace(true);
        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
        }
    }
    if (mContentParent == null) {
        //將ViewGroup添加到DecorView中,並將Content找到,返回
        mContentParent = generateLayout(mDecor);

        mDecor.makeOptionalFitsSystemWindows();

        //自帶裝飾的Content
        //DecorContentParent名字起的也很生動,帶裝飾的
        final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
                R.id.decor_content_parent);

        if (decorContentParent != null) {
            //對decorContentParent的操作
            //設置logo,title,icon,options...
        } else {
            //對Title的一些操作
            //...
        }

        if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
            mDecor.setBackgroundFallback(mBackgroundFallbackResource);
        }

        // Only inflate or create a new TransitionManager if the caller hasn't
        // already set a custom one.
        if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {
            //一些過渡的操作
            //...
        }
    }
}

generateLayout中相關的代碼,有省略

protected ViewGroup generateLayout(DecorView decor) {
    //獲取相關屬性
    TypedArray a = getWindowStyle();

    if (false) {
        //估計是調試用的代碼
        //...
    }

    //各種屬性的設置
    //...

    //ViewGroup的Layout用的id
    int layoutResource;
    int features = getLocalFeatures();
    //根據設置來確定layoutResource是哪個layout
    //...

    //做個開始標記
    mDecor.startChanging();

    //填充ViewGroup
    View in = mLayoutInflater.inflate(layoutResource, null);
    //將ViewGroup添加到DecorView中
    decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    mContentRoot = (ViewGroup) in;

    //獲取Content對象
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

    //一些操作
    //...

    //做個結束標記
    mDecor.finishChanging();

    //返回ViewGroup
    return contentParent;
}

結語

setContentView()相關的代碼還是很多的,需要抓住重點,這樣纔不會影響整體的思維。
如果看完了還是感覺雲裏霧裏,那就先把圖片記住,剩下的以後再說

轉載請標明出處:http://blog.csdn.net/qq_26411333/article/details/51541129

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章