淺談Activity從建立到顯示(setContentView源碼淺析)

本篇文章所分析源碼基于android 6.0.1

一.從setContentView()說起

從我們寫第一個Android程序的時候,就會在MainActivity的onCreat()函數(shù)中寫下setContentView(R.layout.activity_main);這句代碼,我們知道這句是將Activity與xml可視化文件關(guān)聯(lián)的代碼,但是在我們寫下這句代碼的時候,我們有沒有想過這句代碼的背后系統(tǒng)到底做了什么?~~前一陣子被我們組內(nèi)的學長問起這個問題的時候還真是自覺慚愧,無奈前一陣子為了趕項目進度確實沒有時間深究這個問題,今天那我們就來從這句司空見慣的代碼入手,開始我們的View事件分發(fā)機制前傳之旅.
??首先我們將源碼定位到(frameworks/base/core/java/android/app/Activity):

    /**
     * Set the activity content from a layout resource.  The resource will be
     * inflated, adding all top-level views to the activity.
     *
     * @param layoutResID Resource ID to be inflated.
     *
     * @see #setContentView(android.view.View)
     * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
     */
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

可以看到,在我們執(zhí)行setContentView()的時候,源碼中調(diào)用了getWindow().setContentView(layoutResID);這句代碼,那么這個getWindow()得到的是什么東西呢?我們繼續(xù)追蹤源碼(frameworks/base/core/java/android/app/Activity):

    /**
     * Retrieve the current {@link android.view.Window} for the activity.
     * This can be used to directly access parts of the Window API that
     * are not available through Activity/Screen.
     *
     * @return Window The current window, or null if the activity is not
     *         visual.
     */
    public Window getWindow() {
        return mWindow;
    }

根據(jù)這段代碼的注釋的一句:檢索當前Activity的Window(其中{@link android.view.Window}給出的是Window類的地址:frameworks/base/core/java/android/view/Window),以及最后一句@return~~當前的window,或者當activity不可見的時候返回null(這里我們是不是可以get一個點呢?)----從這兩句注釋我們可以看出,這個返回值mWindow是一個Window類型的對象,但是這個Window類是一個抽象類,那么我們繼續(xù)在當前類中須找,看看這個mWindow是在哪里賦值的(frameworks/base/core/java/android/app/Activity):

    private Window mWindow;
    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);

        mWindow = new PhoneWindow(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        ......
    }

在Activity類的attach()方法中我們找到了這么一句mWindow = new PhoneWindow(this);可以看到這里實例化了PhoneWindow類,mWindow是PhoneWindow類的對象,而點開PhoneWindow的源碼我們會發(fā)現(xiàn)它繼承自Window類,由此我們可以知道,PhoneWindow類是Window的具體實現(xiàn)類.
???那么我們繼續(xù)追蹤到PhoneWindow類中,看看他的setContentVeiw()方法實現(xiàn)了什么(frameworks/base/core/java/com/android/internal/policy/PhoneWindow):

    @Override
    public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        if (mContentParent == null) {   //當mContentParent為空的時候,表示當前內(nèi)容還未放置到窗口,也就是第一次調(diào)用的時候
            installDecor(); //  創(chuàng)建并添加DecorView
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {  //如果內(nèi)容已經(jīng)加載過(不是第一次加載),并且不需要動畫,removeAllViews()
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,getContext());
            transitionTo(newScene); //添加完Content后如有設(shè)置了FEATURE_CONTENT_TRANSITIONS則添加Scene來過度啟動
        } else {
            mLayoutInflater.inflate(layoutResID, mContentParent);   //否則將我們的資源文件通過LayoutInflater對象轉(zhuǎn)換為View樹,并且添加至mContentParent視圖中.
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }

(題外話:注意到PhoneWindow類的路徑中有internal這個詞,也就是說這個是內(nèi)部API,我們是不能在開發(fā)中通過SDK來正常調(diào)用的)可以看到在這段代碼中,首先判斷mContentParent是否位null,那么這個mContentParent又是什么鬼呢?

    // This is the view in which the window contents are placed. It is either
    // mDecor itself, or a child of mDecor where the contents go.
    private ViewGroup mContentParent;

結(jié)合注釋:這是放置Window內(nèi)容的View,它或者是mDecor本身,或者是內(nèi)容所在的mDecor的子元素.,注意到這句代碼:mLayoutInflater.inflate(layoutResID, mContentParent);public View inflate (int resource, ViewGroup root) ----可以看到,layoutResID就是我們在MainActivity的setContentView中設(shè)置的R.layout.activity_main,而這個mContentParent是activity_main.xml的父布局~~上面提到了mContentParent是mDecor本身或者是mDecor的一個子元素,這句話是什么意思呢?這個作為(問題)先留下,待會會我們通過源碼分析.
??解釋一下上面的一段代碼----當mContentParent為空的時候,表示當前內(nèi)容還未放置到窗口,也就是第一次調(diào)用的時候,此時調(diào)用installDecor()。這里我們得說一下FEATURE_CONTENT_TRANSITIONS標志位,這個是標記當前內(nèi)容加載有沒有使用過度動畫,也就是轉(zhuǎn)場動畫。如果內(nèi)容已經(jīng)加載過(else表示不是第一次加載),并且不需要動畫,則會調(diào)用removeAllViews()。添加完Content后如有設(shè)置了FEATURE_CONTENT_TRANSITIONS則添加Scene來過度啟動。否則mLayoutInflater.inflate(layoutResID, mContentParent);將我們的資源文件通過LayoutInflater對象轉(zhuǎn)換為View樹,并且添加至mContentParent視圖中。
??整理一下第一節(jié)內(nèi)容:Activity通過PhoneWindow的setContentView方法來設(shè)置布局,而設(shè)置布局之前,會先判斷是否存在mContentParent,而我們設(shè)置的布局文件則是mContentParent的子元素

二.創(chuàng)建DecorView并添加至mContentParent

我們緊接著上面的源碼分析:

    if (mContentParent == null) {
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }

當mContentParent為空的時候,調(diào)用installDecor():

    private void installDecor() {
        if (mDecor == null) {
            mDecor = generateDecor();  ①
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        }
        //一開始DecorView未加載到mContentParent,所以此時mContentParent=null
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor); ②  //該方法將mDecorView添加到Window上綁定布局

            // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
            mDecor.makeOptionalFitsSystemWindows();

            final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
                    R.id.decor_content_parent);

           ......//設(shè)置TitleView(TextView),Backdroud等資源
           ......//設(shè)置有無轉(zhuǎn)場動畫以及轉(zhuǎn)場動畫的種類
        }
    }

首先看①處這段代碼:

    if (mDecor == null) {
        mDecor = generateDecor();
       ......
    }

在這個if中,我們通過generateDecor()方法創(chuàng)建mDecor的實例:

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

這里實例化了DecorView()類,然后呢我們深入到DecorView()類中去看,可以發(fā)現(xiàn)DecorView()類是PhoneWindow()類的一個內(nèi)部類(frameworks/base/core/java/com/android/internal/policy/PhoneWindow):

private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
    /* package */int mDefaultOpacity = PixelFormat.OPAQUE;

    /** The feature ID of the panel, or -1 if this is the application's DecorView */
    private final int mFeatureId;

    ......

    public DecorView(Context context, int featureId) {
        super(context);
        mFeatureId = featureId;

        ......
    }

然后我們注意到②處代碼:

    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor);
        ......

可以看到在這里通過generateLayout()方法將decorView添加到mContentParent中:

    protected ViewGroup generateLayout(DecorView decor) {
        // Apply data from current theme.應用當前theme的數(shù)據(jù),下面一連串的if就是根據(jù)你設(shè)置的theme來判斷當前加載的形式的

        TypedArray a = getWindowStyle();

        ....

        //設(shè)置style為Window_windowNoTitle或者Window_windowActionBar
        if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
            requestFeature(FEATURE_NO_TITLE);
        } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
            // Don't allow an action bar if there is no title.
            requestFeature(FEATURE_ACTION_BAR);
        }

        ....

        //設(shè)置是否全屏
        if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
            setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
        }

        ......//一大堆if判斷style資源

        //這里開始根據(jù)gradle中的targetSdkVersion來判斷是否需要加載菜單欄
        final Context context = getContext();
        final int targetSdk = context.getApplicationInfo().targetSdkVersion;
        final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;
        final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
        final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.LOLLIPOP;
        final boolean targetHcNeedsOptions = context.getResources().getBoolean(
                R.bool.target_honeycomb_needs_options_menu);
        final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);

        if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {
            setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE);
        } else {
            setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_FALSE);
        }

        //高端設(shè)備上的非浮動窗口必須放在系統(tǒng)欄下方,因此必須知道這些窗口的可見性變化。
        // Non-floating windows on high end devices must put up decor beneath the system bars and
        // therefore must know about visibility changes of those.
        if (!mIsFloating && ActivityManager.isHighEndGfx()) {
            if (!targetPreL && a.getBoolean(
                    R.styleable.Window_windowDrawsSystemBarBackgrounds,
                    false)) {
                setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                        FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags());
            }
        }
        ......//省略多個if判斷

        WindowManager.LayoutParams params = getAttributes();

        ......//省略其他加載資源


        // Inflate the window decor.
        //添加布局到DecorView,前面說到,DecorView是繼承與FrameLayout,它本身也是一個ViewGroup,
        //而我們前面創(chuàng)建它的時候,只是調(diào)用了new DecorView,此時里面并無什么東西。而下面的步奏則是根據(jù)
        //用戶設(shè)置的Feature來創(chuàng)建相應的布局主題。
        //舉個例子,如果我在setContentView之前調(diào)用了requestWindowFeature(Window.FEATURE_NO_TITLE),
        //這里則會通過getLocalFeatures來獲取你設(shè)置的feature,進而加載對應的布局,此時是加載沒有標題欄的主題.
        //這也就是為什么我們在代碼中設(shè)置Theme或者requesetFeature()的時候必須在setContentView之前的原因.

        int layoutResource;
        int features = getLocalFeatures();
        // System.out.println("Features: 0x" + Integer.toHexString(features));
        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
            layoutResource = R.layout.screen_swipe_dismiss;
        } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
            if (mIsFloating) {
                TypedValue res = new TypedValue();
                getContext().getTheme().resolveAttribute(
                        R.attr.dialogTitleIconsDecorLayout, res, true);
                layoutResource = res.resourceId;
            } else {
                layoutResource = R.layout.screen_title_icons;
            }
            // XXX Remove this once action bar supports these features.
            removeFeature(FEATURE_ACTION_BAR);
            // System.out.println("Title Icons!");
        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
            ......//一大堆else if條件判斷
        } else {
            // Embedded, so no decoration is needed.
            layoutResource = R.layout.screen_simple;    ③
            // System.out.println("Simple!");
        }

        mDecor.startChanging();

        //選擇對應布局創(chuàng)建添加到DecorView中
        View in = mLayoutInflater.inflate(layoutResource, null);
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));  //往DecorView中添加子View,即mContentParent
        mContentRoot = (ViewGroup) in;

        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        ......

        mDecor.finishChanging();

        return contentParent;
    }

由以上代碼可以看出,該方法還是做了相當多的工作的,首先根據(jù)設(shè)置的主題樣式來設(shè)置DecorView的風格,比如說有沒有titlebar之類的,接著為DecorView添加子View,而這里的子View則是上面提到的mContentParent,如果上面設(shè)置了FEATURE_NO_ACTIONBAR,那么DecorView就只有mContentParent一個子View,這也解釋了上面的疑問:mContentParent是DecorView本身(NO_ACTIONBAR)或者是DecorView的一個子元素(有ACTIONBAR)。
???generateLayout()的返回是contentParent,而它的獲取則是ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
???DecorView是頂級View,它可以標示整個屏幕,其中包含狀態(tài)欄,導航欄,內(nèi)容區(qū)等等。這里的mContentParent指的是屏幕顯示的內(nèi)容區(qū),而我們設(shè)置的activity_main.xml布局則是mContentParent里面的一個子元素。
???注意上面③處的代碼,這個R.layout.screen_simple就是當我們的theme設(shè)置為NoTitleBar時的布局,我們來看看這個文件(SDK/platforms/android-23/data/res/layout/screen_simple.xml):

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">
    <ViewStub android:id="@+id/action_mode_bar_stub"
              android:inflatedId="@+id/action_mode_bar"
              android:layout="@layout/action_mode_bar"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:theme="?attr/actionBarTheme" />
    <FrameLayout
         android:id="@android:id/content"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:foregroundInsidePadding="false"
         android:foregroundGravity="fill_horizontal|top"
         android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>

布局中,一般會包含ActionBar,Title,和一個id為content的FrameLayout,這個布局是NoTitle的。此時我們設(shè)置一個activity,其主界面為activity_main.xml:

<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"    
       android:id="@+id/linearLayout"
       android:layout_width="match_parent"    
       android:layout_height="wrap_content"    
       android:layout_marginTop="50dp" 
       android:paddingBottom="50dp"    
       android:orientation="vertical">    
       <TextView        
            android:id="@+id/textView"       
            android:layout_width="match_parent"     
            android:layout_height="wrap_content"      
            android:text="Hellow word" />    
       <View       
            android:id="@+id/selfView"       
            android:layout_width="match_parent" 
            android:layout_height="100dp" />
</LinearLayout>

我們用下面一張圖來表示activity_main.xml在整個screen_simple.xml中的關(guān)系:

screen_simple.xml中的關(guān)系圖.png

從這張圖我們可以看到,我們平時在APP中所定義的xml文件,實際上是在一個id為content的FrameLayout中的,這個FrameLayout也就是前面一直提到的mContentParent!(我們看源碼的話就會發(fā)現(xiàn),不止screen_simple.xml,screen_toobar.xml,screen_title.xml等等布局文件中都含有這個id為content的FrameLayout)
???我們回到PhoneWindow類的setContentVeiw()方法中:

    @Override
    public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        if (mContentParent == null) {
            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 {
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }

此時通過installDecor()方法已經(jīng)創(chuàng)建完DecorView并且獲取到mContentParent,接著就是將我們setContentView的內(nèi)容添加到mContentParent中,也就是mLayoutInflater.inflate(layoutResID, mContentParent);
???這里我們注意到最后幾句代碼:

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

這里出現(xiàn)了一個回調(diào)接口:cb,通過getCallback()方法,這個方法是Window抽象類中的一個方法:

    /**
     * Set the Callback interface for this window, used to intercept key
     * events and other dynamic operations in the window.
     *
     * @param callback The desired Callback interface.
     */
    public void setCallback(Callback callback) {
        mCallback = callback;
    }

    /**
     * Return the current Callback interface for this window.
     */
    public final Callback getCallback() {
        return mCallback;
    }

一個setCallback(),一個getCallback(),在源碼中就緊挨在一起,所以一并貼出來,而這個setCallback是在Activity類中被調(diào)用的,我們再Activity的attach()方法中發(fā)現(xiàn)了如下代碼:

    final void attach(Context context, ActivityThread aThread,
        ......
        mWindow.setCallback(this);
        ......
    }

再看Activity類本身,它實現(xiàn)了一個特殊的接口:Window.Callback:

    public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback {

也就是說mWindow.setCallback(this);這里的this就是Wondow中的Callback回調(diào)接口。也就是說Activity類實現(xiàn)了Window的Callback接口類中的方法。
現(xiàn)在我們清楚了PhoneWindow中setContentView最后幾句中cb的身世,我們來看看Activity中實現(xiàn)的onContentChanged()方法:

    public void onContentChanged() {
    }

如你所見,onContentChanged是個空方法。而當Activity的布局改動時,即setContentView()或者addContentView()方法執(zhí)行完畢時就會調(diào)用該方法。所以當我們寫App時,Activity的各種View的findViewById()方法等都可以放到該方法中,系統(tǒng)會幫忙回調(diào)。實際上,如果我們看源碼的話就會發(fā)現(xiàn),不光是onContentChanged(),Activity中的onWindowFocusChanged(boolean hasFocus),onAttachedToWindow(),onDetachedFromWindow()......等一系列實現(xiàn)的Widow類中Callback中的方法,都是空方法,這些方法我在開發(fā)當中都可以加以適當?shù)睦?

到目前為止,通過setContentView方法,創(chuàng)建了DecorView和加載了我們提供的布局,但是這時,我們的View還是不可見的,因為我們僅僅是加載了布局,并沒有對View進行任何的測量、布局、繪制工作。在View進行測量流程之前,還要進行一個步驟,那就是把DecorView添加至window中,然后經(jīng)過一系列過程觸發(fā)ViewRootImpl#performTraversals方法,在該方法內(nèi)部會正式開始測量、布局、繪制這三大流程。

三.將DecorView添加至Window并顯示界面

圖片來源于網(wǎng)絡

要解釋DecorView是如何添加到Window的,我們就要從Activity的啟動源碼來講,還記得之前的這篇文章Activity啟動源碼分析(二)——從AMS到Activity
嗎?我們做一個簡單的復習:Activity啟動的過程中必經(jīng)的一步—ActivityThread類中的的handleLaunchActivity()方法(frameworks/base/core/java/android/app/ActivityThread):

    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ......

        Activity a = performLaunchActivity(r, customIntent);    //④

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward,   //⑤
                    !r.activity.mFinished && !r.startsNotResumed);

            ......
            }
        } else {
           ......
        }
    }

我們來看處的方法performLaunchActivity(r, customIntent):

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
        ......

        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);    ⑥
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }

        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            ......

            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                ......

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
                r.lastNonConfigurationInstances = null;
                activity.mStartedActivity = false;
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }

                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);    ⑦
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                ......
            }
            r.paused = true;

            mActivities.put(r.token, r);

        } catch (SuperNotCalledException e) {
            throw e;

        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to start activity " + component
                    + ": " + e.toString(), e);
            }
        }

        return activity;
    }

上篇文章中我們說過Instrumentation類是一個全權(quán)負責Activity生命周期的類,在⑥處的代碼中,通過調(diào)用該類的newActivity()方法(frameworks/base/core/java/android/app/Instrumentation):

    public Activity newActivity(Class<?> clazz, Context context, 
            IBinder token, Application application, Intent intent, ActivityInfo info, 
            CharSequence title, Activity parent, String id,
            Object lastNonConfigurationInstance) throws InstantiationException, 
            IllegalAccessException {
        Activity activity = (Activity)clazz.newInstance();
        ActivityThread aThread = null;
        activity.attach(context, aThread, this, token, 0, application, intent,
                info, title, parent, id,
                (Activity.NonConfigurationInstances)lastNonConfigurationInstance,
                new Configuration(), null, null);
        return activity;
    }

創(chuàng)建了一個新的Activity實例,在改方法中調(diào)用了Activity類中的attach()方法,之后在中的代碼中,調(diào)用了Instrumentation類的callActivityOnCreate方法:

    /**
     * Perform calling of an activity's {@link Activity#onCreate}
     * method.  The default implementation simply calls through to that method.
     *
     * @param activity The activity being created.
     * @param icicle The previously frozen state (or null) to pass through to onCreate().
     */
    public void callActivityOnCreate(Activity activity, Bundle icicle) {
        prePerformCreate(activity);
        activity.performCreate(icicle);
        postPerformCreate(activity);
    }

調(diào)用了Activity類中的performCreate()方法(frameworks/base/core/java/android/app/Activity):

    final void performCreate(Bundle icicle) {
        restoreHasCurrentPermissionRequest(icicle);
        onCreate(icicle);
        mActivityTransitionState.readState(icicle);
        performCreateCommon();
    }

調(diào)用了onCreate(icicle);方法:

    /**
     * Called when the activity is starting.  This is where most initialization
     * should go: calling {@link #setContentView(int)} to inflate the
     * activity's UI, using {@link #findViewById} to programmatically interact
     * with widgets in the UI, calling
     * {@link #managedQuery(android.net.Uri , String[], String, String[], String)} to retrieve
     * cursors for data being displayed, etc.
     *
     * <p>You can call {@link #finish} from within this function, in
     * which case onDestroy() will be immediately called without any of the rest
     * of the activity lifecycle ({@link #onStart}, {@link #onResume},
     * {@link #onPause}, etc) executing.
     *
     * <p><em>Derived classes must call through to the super class's
     * implementation of this method.  If they do not, an exception will be
     * thrown.</em></p>
     *
     * @param savedInstanceState If the activity is being re-initialized after
     *     previously being shut down then this Bundle contains the data it most
     *     recently supplied in {@link #onSaveInstanceState}.  <b><i>Note: Otherwise it is null.</i></b>
     *
     * @see #onStart
     * @see #onSaveInstanceState
     * @see #onRestoreInstanceState
     * @see #onPostCreate
     */
    @MainThread
    @CallSuper
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
        if (mLastNonConfigurationInstances != null) {
            mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
        }
        if (mActivityInfo.parentActivityName != null) {
            if (mActionBar == null) {
                mEnableDefaultActionBarUp = true;
            } else {
                mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
            }
        }
        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                    ? mLastNonConfigurationInstances.fragments : null);
        }
        mFragments.dispatchCreate();
        getApplication().dispatchActivityCreated(this, savedInstanceState);
        if (mVoiceInteractor != null) {
            mVoiceInteractor.attachActivity(this);
        }
        mCalled = true;
    }

在這里,我們看注釋也知道,這個就是Activity第一個生命周期:onCreat(),在這里調(diào)用setContentView().⑥⑦流程走完了之后,整個performLaunchActivity()函數(shù)就會返回一個已經(jīng)執(zhí)行完onCreat()和setContetnView()的activity對象,然而正如我們之前所說,setContentView()執(zhí)行完之后,View此時還是不可見的,要等DecorView添加至window中,然后觸發(fā)ViewRootImpl#performTraversals方法開始View的繪制,測量等工作.
???回到ActivityThread類中的看⑤處方法
handleResumeActivity();(frameworks/base/core/java/android/app/ActivityThread):

    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
        ......
        // TODO Push resumeArgs into the activity for consideration
        ActivityClientRecord r = performResumeActivity(token, clearHide);   ⑧

        if (r != null) {
            final Activity a = r.activity;
            ......

            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();  ⑨
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();

                WindowManager.LayoutParams l = r.window.getAttributes();    ⑩
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                }

            // If the window has already been added, but during resume
            // we started another activity, then don't yet make the
            // window visible.
            } else if (!willBeVisible) {
                if (localLOGV) Slog.v(
                    TAG, "Launch " + r + " mStartedActivity set");
                r.hideForNow = true;
            }

            // Get rid of anything left hanging around.
            cleanUpPendingRemoveWindows(r);

            // The window is now visible if it has been added, we are not
            // simply finishing, and we are not starting another activity.
            if (!r.activity.mFinished && willBeVisible
                    && r.activity.mDecor != null && !r.hideForNow) {
                ......
                WindowManager.LayoutParams l = r.window.getAttributes();
                if ((l.softInputMode
                        & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
                        != forwardBit) {
                    l.softInputMode = (l.softInputMode
                            & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
                            | forwardBit;
                    if (r.activity.mVisibleFromClient) {
                        ViewManager wm = a.getWindowManager();
                        View decor = r.window.getDecorView();
                        wm.updateViewLayout(decor, l);
                    }
                }
                r.activity.mVisibleFromServer = true;
                mNumVisibleActivities++;
                if (r.activity.mVisibleFromClient) {
                    r.activity.makeVisible();       (11)
                }
            }
            ......
        } else {
            // If an exception was thrown when trying to resume, then
            // just end this activity.
            try {
                ActivityManagerNative.getDefault()
                    .finishActivity(token, Activity.RESULT_CANCELED, null, false);
            } catch (RemoteException ex) {
            }
        }
    }

注意到⑧處performResumeActivity(token, clearHide)方法,聯(lián)系performLaunchActivity(),我們可以猜到這個方法是與onResume()方法有關(guān)的:

    public final ActivityClientRecord performResumeActivity(IBinder token,
            boolean clearHide) {
        ActivityClientRecord r = mActivities.get(token);
        ......
        if (r != null && !r.activity.mFinished) {
            ......
            try {
                r.activity.onStateNotSaved();
                r.activity.mFragments.noteStateNotSaved();
                if (r.pendingIntents != null) {
                    deliverNewIntents(r, r.pendingIntents);
                    r.pendingIntents = null;
                }
                if (r.pendingResults != null) {
                    deliverResults(r, r.pendingResults);
                    r.pendingResults = null;
                }
                r.activity.performResume();     (12)
                ......

                r.paused = false;
                r.stopped = false;
                r.state = null;
                r.persistentState = null;
            } catch (Exception e) {
                ......
            }
        }
        return r;
    }

可以看到,這個方法中(12)處調(diào)用了Activity類中的performResume()方法:

    final void performResume() {
        ......
        // mResumed is set by the instrumentation
        mInstrumentation.callActivityOnResume(this);

        ......
        onPostResume();
        if (!mCalled) {
            throw new SuperNotCalledException(
                "Activity " + mComponent.toShortString() +
                " did not call through to super.onPostResume()");
        }
    }

調(diào)用了Instrumentation類中的callActivityOnResume()方法()(frameworks/base/core/java/android/app/Instrumentation):

    public void callActivityOnResume(Activity activity) {
        activity.mResumed = true;
        activity.onResume();

        ......
    }

調(diào)用了Activity生命周期中的onResume()方法:

    /**
     * Called after {@link #onRestoreInstanceState}, {@link #onRestart}, or
     * {@link #onPause}, for your activity to start interacting with the user.
     * This is a good place to begin animations, open exclusive-access devices
     * (such as the camera), etc.
     *
     * <p>Keep in mind that onResume is not the best indicator that your activity
     * is visible to the user; a system window such as the keyguard may be in
     * front.  Use {@link #onWindowFocusChanged} to know for certain that your
     * activity is visible to the user (for example, to resume a game).
     *
     * <p><em>Derived classes must call through to the super class's
     * implementation of this method.  If they do not, an exception will be
     * thrown.</em></p>
     *
     * @see #onRestoreInstanceState
     * @see #onRestart
     * @see #onPostResume
     * @see #onPause
     */
    @CallSuper
    protected void onResume() {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
        getApplication().dispatchActivityResumed(this);
        mActivityTransitionState.onResume();
        mCalled = true;
    }

回到handleResumeActivity()方法⑧處,由這一段的分析可知:⑧處的代碼(ActivityClientRecord r = performResumeActivity(token, clearHide);)執(zhí)行完后,Activity的onResume()方法也就執(zhí)行完了,此時返回一個改變了必要參數(shù)或者說必要變量賦值的ActivityClientRecord的對象r,這個ActivityClientRecord是ActivityThread類中的內(nèi)部實體類,分裝了ActivityThread執(zhí)行過程中必要的變量和對象,包括window,DecorView等.
???緊接著我們看⑨處的幾句代碼:

    r.window = r.activity.getWindow();
    View decor = r.window.getDecorView();   ⑨
    decor.setVisibility(View.INVISIBLE);
    ViewManager wm = a.getWindowManager();

r.window = r.activity.getWindow();獲得當前Activity的PhoneWindow對象,之前已經(jīng)分析過了,getWindow()方法返回的是mWindow,也就是PhoneWindow對象.
View decor = r.window.getDecorView();獲得當前phoneWindow內(nèi)部類DecorView對象.
decor.setVisibility(View.INVISIBLE);剛獲得這個DecorView的時候先設(shè)置為不可見.
ViewManager wm = a.getWindowManager();創(chuàng)建一個ViewManager對象,這句要重點說一下:
首先調(diào)用Activity的getWindowManager()方法:

    /** Retrieve the window manager for showing custom windows. */
    public WindowManager getWindowManager() {
        return mWindowManager;
    }

Activity類中mWindowManager唯一賦值的地方在attach()方法中:

    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
        ......

        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;
    }

調(diào)用了Window的getWindowManager()方法:

    /**
     * Return the window manager allowing this Window to display its own
     * windows.
     *
     * @return WindowManager The ViewManager.
     */
    public WindowManager getWindowManager() {
        return mWindowManager;
    }

Window類中mWindowManager唯一賦值的地方在:

    /**
     * Set the window manager for use by this Window to, for example,
     * display panels.  This is <em>not</em> used for displaying the
     * Window itself -- that must be done by the client.
     *
     * @param wm The window manager for adding new windows.
     */
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

調(diào)用了createLocalWindowManager()方法(frameworks/base/core/java/android/view/WindowManagerImpl):

    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }

返回了一個WindowManagerImpl類的實例.也就是說⑨處的代碼ViewManager wm = a.getWindowManager();返回的wm是一個WindowManagerImpl類的實例.
而這個方法在mWindowManager = mWindow.getWindowManager();這句之前就已經(jīng)調(diào)用過了,我們分析一下:這個方法中出現(xiàn)了兩個類:WindowManager和WindowManagerImpl,而⑨處的代碼中第四行ViewManager wm = a.getWindowManager();中又有一個ViewManager類,我們來看看這三個類的關(guān)系(frameworks/base/core/java/android/view/ViewManager):

public interface ViewManager{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}
public interface WindowManager extends ViewManager {
public final class WindowManagerImpl implements WindowManager {

Window是一個抽象的概念,每一個Window都對應著一個View和一個ViewRootImpl,Window又通過ViewRootImpl與View建立聯(lián)系,因此Window并不是實際存在的,他是以View的形式體現(xiàn)的。這點從WindowManager的定義也可以看出,它繼承的的三個接口方法addView,updateView,removeView都是針對View的,這說明View才是Window的實體!?在實際使用中無法直接訪問Window,對Window的操作(添加,更新,刪除)必須通過WindowManager,并且都是在ViewRootImpl中實現(xiàn)的。
??WindowManager顧名思義就是管理Window的類,WindowManager操作Window的過程更像是在操作Window中的View,常用的只有三個方法,即添加View,更新View和刪除View,這三個方法定義在ViewManager中,而WindowManager繼承了ViewManager(當然WindowManager還有其它功能,比如改變Window的位置等),但是WindowManager也是一個接口,真正實現(xiàn)它的類是WindowManagerImpl類,WindowManagerImpl又將所有操作委托給WindowManagerGlobal,當然最終還是在ViewRootImpl中實現(xiàn)的.
???下面我們回到ActivityThread類中handleResumeActivity()方法中的⑩處:

    WindowManager.LayoutParams l = r.window.getAttributes();    ⑩
    a.mDecor = decor;
    l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
    l.softInputMode |= forwardBit;
    if (a.mVisibleFromClient) {
        a.mWindowAdded = true;  //標記根布局DecorView已經(jīng)添加到窗口
        wm.addView(decor, l);   //將根布局DecorView(decor)以當前Window的布局參數(shù)(l)
                                //添加到當前Activity的窗口(WindowManagerImpl對象wm)上面
    }

l是當前Window(View)的布局參數(shù),然后又將當前DecorVeiw賦給當前Activity的mDecor,我們重點追蹤wm.addView(decor, l);這句代碼,先是WindowManagerImpl類中的addView()方法這里比較重要的一點就是完成了DecorView添加到Window的過程 ~~ wm.addView(decor, l);
(frameworks/base/core/java/android/view/WindowManagerImpl):

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }

調(diào)用了WindowManagerGlobal類中的addView()方法(frameworks/base/core/java/android/view/WindowManagerGlobal):

    //表示View樹的根節(jié)點
    private final ArrayList<View> mViews = new ArrayList<View>();
    //表示ViewRootImpl,一個根view對應一個ViewRootImpl
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    //表示根view的WindowManager.LayoutParams
    private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>();
        ......

    public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow) {
        ......
        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            ......
             // If this is a panel window, then find the window it is being
            // attached to for future reference.
            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                final int count = mViews.size();
                for (int i = 0; i < count; i++) {
                    if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                        panelParentView = mViews.get(i);
                    }
                }
            }

            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);

            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }

        // do this last because it fires off messages to start doing things
        try {
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            // BadTokenException or InvalidDisplayException, clean up.
            synchronized (mLock) {
                final int index = findViewLocked(view, false);
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
            }
            throw e;
        }
    }

可以看到這里出現(xiàn)了ViewRootImpl類的實例root,而經(jīng)過層層傳遞,這里傳進來的參數(shù)View就是decor,也就是DecorVeiw,注意這里調(diào)用了root.setView(view, wparams, panelParentView);
(frameworks/base/core/java/android/view/ViewRootImpl):

    /**
     * We have one child
     */
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;   //傳進來的view(也就是DecorView)賦給了mView.

               ......
                mAdded = true;  //表示已成功添加DecorView的標志位
                int res; /* = WindowManagerImpl.ADD_OKAY; */

                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
                requestLayout();  //完成異步刷新請求,重繪界面
                ......
                try {
                    ......
                    //通過WindowSession最終完成window的添加過程, WindowSession內(nèi)部通過WindowManagerService來實現(xiàn)Window的添加
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } catch (RemoteException e) {
                    mAdded = false;
                   ......
                    throw new RuntimeException("Adding window failed", e);
                } finally {
                    if (restore) {
                        attrs.restore();
                    }
                }
        }
    }

這個方法有點略長(200多行),我們只看關(guān)鍵方法:
requestLayout()該方法最終開始界面的測量繪制等操作.
mWindowSession.addToDisplay()這個方法最終完成的是Window的添加過程(具體添加的過程這里就不展開了);

    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

調(diào)用到了** mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);**,這個方法在Choreographer類中的具體實現(xiàn)牽扯到了native層的代碼,本文不做具體分析,我們只看這里注冊了一個回調(diào)接口,調(diào)用了mTraversalRunnable這個Runnable對象,于是我們順藤摸瓜(還是在ViewRootImpl類中):

    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }
    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

調(diào)用了doTraversal()方法:

    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }

            performTraversals();

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }

調(diào)用到了performTraversals()方法:

    private void performTraversals() {
        // cache mView since it is used so much below...
        final View host = mView;    //mView就是DecorView根布局
        if (host == null || !mAdded)    //變量mAdded已被賦值為true,因此條件不成立
            return;
        mIsInTraversal = true;  //是否正在遍歷
        mWillDrawSoon = true;    //是否馬上繪制View

       ......
        int desiredWindowWidth;  //頂層視圖DecorView所需要窗口的寬度和高度
        int desiredWindowHeight;

        ......
        if (mFirst) {   //在構(gòu)造方法中mFirst已經(jīng)設(shè)置為true,表示是否是第一次繪制DecorView
            mFullRedrawNeeded = true;
            mLayoutRequested = true;
            //如果窗口的類型是有狀態(tài)欄的,那么頂層視圖DecorView所需要窗口的寬度和高度就是除了狀態(tài)欄
            if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
                    || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
                // NOTE -- system code, won't try to do compat mode.
                Point size = new Point();
                mDisplay.getRealSize(size);
                desiredWindowWidth = size.x;
                desiredWindowHeight = size.y;
            } else {//否則頂層視圖DecorView所需要窗口的寬度和高度就是整個屏幕的寬高
                DisplayMetrics packageMetrics =
                    mView.getContext().getResources().getDisplayMetrics();
                desiredWindowWidth = packageMetrics.widthPixels;
                desiredWindowHeight = packageMetrics.heightPixels;
            }
        }
        ......
        //獲得view寬高的測量規(guī)格,mWidth和mHeight表示窗口的寬高,lp.widthhe和lp.height表示DecorView根布局寬和高
        int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
        int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);

        // Ask host how big it wants to be
        //執(zhí)行測量操作
        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);

        ......
        //執(zhí)行布局操作
        performLayout(lp, desiredWindowWidth, desiredWindowHeight);

        ......
        //執(zhí)行繪制操作
        performDraw();

    }

可以看到,在這個方法中開始了View的測量、布局、繪制流程三大流程,這個在之后會另起文章分析.
???回到ActivityThread類中的handleResumeActivity()方法
(frameworks/base/core/java/android/app/ActivityThread):

    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
        ......
        // TODO Push resumeArgs into the activity for consideration
        ActivityClientRecord r = performResumeActivity(token, clearHide);   ⑧

        if (r != null) {
            final Activity a = r.activity;
            ......

            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();  ⑨
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();

                WindowManager.LayoutParams l = r.window.getAttributes();    ⑩
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                }

            // If the window has already been added, but during resume
            // we started another activity, then don't yet make the
            // window visible.
            } else if (!willBeVisible) {
                if (localLOGV) Slog.v(
                    TAG, "Launch " + r + " mStartedActivity set");
                r.hideForNow = true;
            }

            // Get rid of anything left hanging around.
            cleanUpPendingRemoveWindows(r);

            // The window is now visible if it has been added, we are not
            // simply finishing, and we are not starting another activity.
            if (!r.activity.mFinished && willBeVisible
                    && r.activity.mDecor != null && !r.hideForNow) {
                ......
                WindowManager.LayoutParams l = r.window.getAttributes();
                if ((l.softInputMode
                        & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
                        != forwardBit) {
                    l.softInputMode = (l.softInputMode
                            & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
                            | forwardBit;
                    if (r.activity.mVisibleFromClient) {
                        ViewManager wm = a.getWindowManager();
                        View decor = r.window.getDecorView();
                        wm.updateViewLayout(decor, l);
                    }
                }
                r.activity.mVisibleFromServer = true;
                mNumVisibleActivities++;
                if (r.activity.mVisibleFromClient) {
                    r.activity.makeVisible();       (11)
                }
            }
            ......
        } else {
            // If an exception was thrown when trying to resume, then
            // just end this activity.
            try {
                ActivityManagerNative.getDefault()
                    .finishActivity(token, Activity.RESULT_CANCELED, null, false);
            } catch (RemoteException ex) {
            }
        }
    }

經(jīng)過上面的分析,⑧⑨⑩處代碼執(zhí)行完之后,DecorView才添加到了Window中,但是由于decor.setVisibility(View.INVISIBLE);導致它目前還是不可見的,而真正顯現(xiàn)是在(11)處的代碼(調(diào)用了Activity類中的makeVisible()方法):

    void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }

可以看到,mDecor.setVisibility(View.VISIBLE);,此時DecorView才是真正的可以看見了,界面也就顯示出來了!從Activity的生命周期的角度來看,也就是onResume()執(zhí)行完之后,DecorView才開始attach給WindowManager從而顯示出來.
Activity的內(nèi)部實際上持有了一個Window的子類PhoneWindow。Activity中關(guān)于界面的繪制實際上是交給PhoneWindow中的setContentView方法來實現(xiàn)。

我們總結(jié)一下:
??1.Activity在onCreate之前調(diào)用attach方法,在attach方法中會創(chuàng)建window對象。window對象創(chuàng)建時并沒有創(chuàng)建Decor對象。用戶在Activity中調(diào)用setContentView,然后調(diào)用window的setContentView,這時會檢查DecorView是否存在,如果不存在則創(chuàng)建DecorView對象,然后把用戶自己的View 添加到DecorView中
??2.①Window是一個抽象類,提供了各種窗口操作的方法,比如設(shè)置背景標題ContentView等等
??②PhoneWindow則是Window的唯一實現(xiàn)類,它里面實現(xiàn)了各種添加背景主題ContentView的方法,內(nèi)部通過DecorView來添加頂級視圖
??③每一個Activity上面都有一個Window,可以通過getWindow獲取DecorView,頂級視圖,繼承于FramentLayout,setContentView則是添加在它里面的@id/content里
??④setContentView里面創(chuàng)建了DecorView,根據(jù)Theme/Feature添加了對應的布局文件,當setContentView設(shè)置顯示后會回調(diào)Activity的onContentChanged方法

??至此,除去View的繪制流程,setContentView()的源碼就分析完了,撒花!!!

站在巨人的肩膀上摘蘋果:
Android View源碼解讀:淺談DecorView與ViewRootImpl

Android應用setContentView與LayoutInflater加載解析機制源碼分析
Android窗口機制(二)Window,PhoneWindow,DecorView,setContentView源碼理解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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