浅谈Activity从建立到显示(setContentView源

作者: Geeks_Liu | 来源:发表于2017-01-24 22:18 被阅读1695次
    本篇文章所分析源码基于android 6.0.1

    一.从setContentView()说起

    从我们写第一个Android程序的时候,就会在MainActivity的onCreat()函数中写下setContentView(R.layout.activity_main);这句代码,我们知道这句是将Activity与xml可视化文件关联的代码,但是在我们写下这句代码的时候,我们有没有想过这句代码的背后系统到底做了什么?~~前一阵子被我们组内的学长问起这个问题的时候还真是自觉惭愧,无奈前一阵子为了赶项目进度确实没有时间深究这个问题,今天那我们就来从这句司空见惯的代码入手,开始我们的View事件分发机制前传之旅.
      首先我们将源码定位到(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();
        }
    

    可以看到,在我们执行setContentView()的时候,源码中调用了getWindow().setContentView(layoutResID);这句代码,那么这个getWindow()得到的是什么东西呢?我们继续追踪源码(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;
        }
    

    根据这段代码的注释的一句:检索当前Activity的Window(其中{@link android.view.Window}给出的是Window类的地址:frameworks/base/core/java/android/view/Window),以及最后一句@return~~当前的window,或者当activity不可见的时候返回null(这里我们是不是可以get一个点呢?)----从这两句注释我们可以看出,这个返回值mWindow是一个Window类型的对象,但是这个Window类是一个抽象类,那么我们继续在当前类中须找,看看这个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的源码我们会发现它继承自Window类,由此我们可以知道,PhoneWindow类是Window的具体实现类.
       那么我们继续追踪到PhoneWindow类中,看看他的setContentVeiw()方法实现了什么(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为空的时候,表示当前内容还未放置到窗口,也就是第一次调用的时候
                installDecor(); //  创建并添加DecorView
            } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {  //如果内容已经加载过(不是第一次加载),并且不需要动画,removeAllViews()
                mContentParent.removeAllViews();
            }
    
            if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
                final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,getContext());
                transitionTo(newScene); //添加完Content后如有设置了FEATURE_CONTENT_TRANSITIONS则添加Scene来过度启动
            } else {
                mLayoutInflater.inflate(layoutResID, mContentParent);   //否则将我们的资源文件通过LayoutInflater对象转换为View树,并且添加至mContentParent视图中.
            }
            mContentParent.requestApplyInsets();
            final Callback cb = getCallback();
            if (cb != null && !isDestroyed()) {
                cb.onContentChanged();
            }
        }
    

    (题外话:注意到PhoneWindow类的路径中有internal这个词,也就是说这个是内部API,我们是不能在开发中通过SDK来正常调用的)可以看到在这段代码中,首先判断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;
    

    结合注释:这是放置Window内容的View,它或者是mDecor本身,或者是内容所在的mDecor的子元素.,注意到这句代码:mLayoutInflater.inflate(layoutResID, mContentParent);public View inflate (int resource, ViewGroup root) ----可以看到,layoutResID就是我们在MainActivity的setContentView中设置的R.layout.activity_main,而这个mContentParent是activity_main.xml的父布局~~上面提到了mContentParent是mDecor本身或者是mDecor的一个子元素,这句话是什么意思呢?这个作为(问题)先留下,待会会我们通过源码分析.
      解释一下上面的一段代码----当mContentParent为空的时候,表示当前内容还未放置到窗口,也就是第一次调用的时候,此时调用installDecor()。这里我们得说一下FEATURE_CONTENT_TRANSITIONS标志位,这个是标记当前内容加载有没有使用过度动画,也就是转场动画。如果内容已经加载过(else表示不是第一次加载),并且不需要动画,则会调用removeAllViews()。添加完Content后如有设置了FEATURE_CONTENT_TRANSITIONS则添加Scene来过度启动。否则mLayoutInflater.inflate(layoutResID, mContentParent);将我们的资源文件通过LayoutInflater对象转换为View树,并且添加至mContentParent视图中。
      整理一下第一节内容:Activity通过PhoneWindow的setContentView方法来设置布局,而设置布局之前,会先判断是否存在mContentParent,而我们设置的布局文件则是mContentParent的子元素

    二.创建DecorView并添加至mContentParent

    我们紧接着上面的源码分析:

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

    当mContentParent为空的时候,调用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);
    
               ......//设置TitleView(TextView),Backdroud等资源
               ......//设置有无转场动画以及转场动画的种类
            }
        }
    

    首先看①处这段代码:

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

    在这个if中,我们通过generateDecor()方法创建mDecor的实例:

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

    这里实例化了DecorView()类,然后呢我们深入到DecorView()类中去看,可以发现DecorView()类是PhoneWindow()类的一个内部类(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的数据,下面一连串的if就是根据你设置的theme来判断当前加载的形式的
    
            TypedArray a = getWindowStyle();
    
            ....
    
            //设置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);
            }
    
            ....
    
            //设置是否全屏
            if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
                setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
            }
    
            ......//一大堆if判断style资源
    
            //这里开始根据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);
            }
    
            //高端设备上的非浮动窗口必须放在系统栏下方,因此必须知道这些窗口的可见性变化。
            // 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,
            //而我们前面创建它的时候,只是调用了new DecorView,此时里面并无什么东西。而下面的步奏则是根据
            //用户设置的Feature来创建相应的布局主题。
            //举个例子,如果我在setContentView之前调用了requestWindowFeature(Window.FEATURE_NO_TITLE),
            //这里则会通过getLocalFeatures来获取你设置的feature,进而加载对应的布局,此时是加载没有标题栏的主题.
            //这也就是为什么我们在代码中设置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();
    
            //选择对应布局创建添加到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;
        }
    

    由以上代码可以看出,该方法还是做了相当多的工作的,首先根据设置的主题样式来设置DecorView的风格,比如说有没有titlebar之类的,接着为DecorView添加子View,而这里的子View则是上面提到的mContentParent,如果上面设置了FEATURE_NO_ACTIONBAR,那么DecorView就只有mContentParent一个子View,这也解释了上面的疑问:mContentParent是DecorView本身(NO_ACTIONBAR)或者是DecorView的一个子元素(有ACTIONBAR)。
       generateLayout()的返回是contentParent,而它的获取则是ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
       DecorView是顶级View,它可以标示整个屏幕,其中包含状态栏,导航栏,内容区等等。这里的mContentParent指的是屏幕显示的内容区,而我们设置的activity_main.xml布局则是mContentParent里面的一个子元素。
       注意上面③处的代码,这个R.layout.screen_simple就是当我们的theme设置为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的。此时我们设置一个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中的关系:

    screen_simple.xml中的关系图.png

    从这张图我们可以看到,我们平时在APP中所定义的xml文件,实际上是在一个id为content的FrameLayout中的,这个FrameLayout也就是前面一直提到的mContentParent!(我们看源码的话就会发现,不止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()方法已经创建完DecorView并且获取到mContentParent,接着就是将我们setContentView的内容添加到mContentParent中,也就是mLayoutInflater.inflate(layoutResID, mContentParent);
       这里我们注意到最后几句代码:

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

    这里出现了一个回调接口: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类中被调用的,我们再Activity的attach()方法中发现了如下代码:

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

    再看Activity类本身,它实现了一个特殊的接口:Window.Callback:

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

    也就是说mWindow.setCallback(this);这里的this就是Wondow中的Callback回调接口。也就是说Activity类实现了Window的Callback接口类中的方法。
    现在我们清楚了PhoneWindow中setContentView最后几句中cb的身世,我们来看看Activity中实现的onContentChanged()方法:

        public void onContentChanged() {
        }
    

    如你所见,onContentChanged是个空方法。而当Activity的布局改动时,即setContentView()或者addContentView()方法执行完毕时就会调用该方法。所以当我们写App时,Activity的各种View的findViewById()方法等都可以放到该方法中,系统会帮忙回调。实际上,如果我们看源码的话就会发现,不光是onContentChanged(),Activity中的onWindowFocusChanged(boolean hasFocus),onAttachedToWindow(),onDetachedFromWindow()......等一系列实现的Widow类中Callback中的方法,都是空方法,这些方法我在开发当中都可以加以适当的利用.

    到目前为止,通过setContentView方法,创建了DecorView和加载了我们提供的布局,但是这时,我们的View还是不可见的,因为我们仅仅是加载了布局,并没有对View进行任何的测量、布局、绘制工作。在View进行测量流程之前,还要进行一个步骤,那就是把DecorView添加至window中,然后经过一系列过程触发ViewRootImpl#performTraversals方法,在该方法内部会正式开始测量、布局、绘制这三大流程。

    三.将DecorView添加至Window并显示界面

    图片来源于网络

    要解释DecorView是如何添加到Window的,我们就要从Activity的启动源码来讲,还记得之前的这篇文章Activity启动源码分析(二)——从AMS到Activity
    吗?我们做一个简单的复习:Activity启动的过程中必经的一步—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类是一个全权负责Activity生命周期的类,在⑥处的代码中,通过调用该类的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;
        }
    

    创建了一个新的Activity实例,在改方法中调用了Activity类中的attach()方法,之后在中的代码中,调用了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);
        }
    

    调用了Activity类中的performCreate()方法(frameworks/base/core/java/android/app/Activity):

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

    调用了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(),在这里调用setContentView().⑥⑦流程走完了之后,整个performLaunchActivity()函数就会返回一个已经执行完onCreat()和setContetnView()的activity对象,然而正如我们之前所说,setContentView()执行完之后,View此时还是不可见的,要等DecorView添加至window中,然后触发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)方法,联系performLaunchActivity(),我们可以猜到这个方法是与onResume()方法有关的:

        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)处调用了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()");
            }
        }
    

    调用了Instrumentation类中的callActivityOnResume()方法()(frameworks/base/core/java/android/app/Instrumentation):

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

    调用了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);)执行完后,Activity的onResume()方法也就执行完了,此时返回一个改变了必要参数或者说必要变量赋值的ActivityClientRecord的对象r,这个ActivityClientRecord是ActivityThread类中的内部实体类,分装了ActivityThread执行过程中必要的变量和对象,包括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对象,之前已经分析过了,getWindow()方法返回的是mWindow,也就是PhoneWindow对象.
    View decor = r.window.getDecorView();获得当前phoneWindow内部类DecorView对象.
    decor.setVisibility(View.INVISIBLE);刚获得这个DecorView的时候先设置为不可见.
    ViewManager wm = a.getWindowManager();创建一个ViewManager对象,这句要重点说一下:
    首先调用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;
        }
    

    调用了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);
        }
    

    调用了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();这句之前就已经调用过了,我们分析一下:这个方法中出现了两个类:WindowManager和WindowManagerImpl,而⑨处的代码中第四行ViewManager wm = a.getWindowManager();中又有一个ViewManager类,我们来看看这三个类的关系(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建立联系,因此Window并不是实际存在的,他是以View的形式体现的。这点从WindowManager的定义也可以看出,它继承的的三个接口方法addView,updateView,removeView都是针对View的,这说明View才是Window的实体! 在实际使用中无法直接访问Window,对Window的操作(添加,更新,删除)必须通过WindowManager,并且都是在ViewRootImpl中实现的。
      WindowManager顾名思义就是管理Window的类,WindowManager操作Window的过程更像是在操作Window中的View,常用的只有三个方法,即添加View,更新View和删除View,这三个方法定义在ViewManager中,而WindowManager继承了ViewManager(当然WindowManager还有其它功能,比如改变Window的位置等),但是WindowManager也是一个接口,真正实现它的类是WindowManagerImpl类,WindowManagerImpl又将所有操作委托给WindowManagerGlobal,当然最终还是在ViewRootImpl中实现的.
       下面我们回到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已经添加到窗口
            wm.addView(decor, l);   //将根布局DecorView(decor)以当前Window的布局参数(l)
                                    //添加到当前Activity的窗口(WindowManagerImpl对象wm)上面
        }
    

    l是当前Window(View)的布局参数,然后又将当前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);
        }
    

    调用了WindowManagerGlobal类中的addView()方法(frameworks/base/core/java/android/view/WindowManagerGlobal):

        //表示View树的根节点
        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;
            }
        }
    

    可以看到这里出现了ViewRootImpl类的实例root,而经过层层传递,这里传进来的参数View就是decor,也就是DecorVeiw,注意这里调用了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内部通过WindowManagerService来实现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多行),我们只看关键方法:
    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();
            }
        }
    

    调用到了** mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);**,这个方法在Choreographer类中的具体实现牵扯到了native层的代码,本文不做具体分析,我们只看这里注册了一个回调接口,调用了mTraversalRunnable这个Runnable对象,于是我们顺藤摸瓜(还是在ViewRootImpl类中):

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

    调用了doTraversal()方法:

        void doTraversal() {
            if (mTraversalScheduled) {
                mTraversalScheduled = false;
                mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
    
                if (mProfile) {
                    Debug.startMethodTracing("ViewAncestor");
                }
    
                performTraversals();
    
                if (mProfile) {
                    Debug.stopMethodTracing();
                    mProfile = false;
                }
            }
        }
    

    调用到了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) {   //在构造方法中mFirst已经设置为true,表示是否是第一次绘制DecorView
                mFullRedrawNeeded = true;
                mLayoutRequested = true;
                //如果窗口的类型是有状态栏的,那么顶层视图DecorView所需要窗口的宽度和高度就是除了状态栏
                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宽高的测量规格,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
            //执行测量操作
            performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    
            ......
            //执行布局操作
            performLayout(lp, desiredWindowWidth, desiredWindowHeight);
    
            ......
            //执行绘制操作
            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) {
                }
            }
        }
    

    经过上面的分析,⑧⑨⑩处代码执行完之后,DecorView才添加到了Window中,但是由于decor.setVisibility(View.INVISIBLE);导致它目前还是不可见的,而真正显现是在(11)处的代码(调用了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()执行完之后,DecorView才开始attach给WindowManager从而显示出来.
    Activity的内部实际上持有了一个Window的子类PhoneWindow。Activity中关于界面的绘制实际上是交给PhoneWindow中的setContentView方法来实现。

    我们总结一下:
      1.Activity在onCreate之前调用attach方法,在attach方法中会创建window对象。window对象创建时并没有创建Decor对象。用户在Activity中调用setContentView,然后调用window的setContentView,这时会检查DecorView是否存在,如果不存在则创建DecorView对象,然后把用户自己的View 添加到DecorView中
      2.①Window是一个抽象类,提供了各种窗口操作的方法,比如设置背景标题ContentView等等
      ②PhoneWindow则是Window的唯一实现类,它里面实现了各种添加背景主题ContentView的方法,内部通过DecorView来添加顶级视图
      ③每一个Activity上面都有一个Window,可以通过getWindow获取DecorView,顶级视图,继承于FramentLayout,setContentView则是添加在它里面的@id/content里
      ④setContentView里面创建了DecorView,根据Theme/Feature添加了对应的布局文件,当setContentView设置显示后会回调Activity的onContentChanged方法

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

    站在巨人的肩膀上摘苹果:
    Android View源码解读:浅谈DecorView与ViewRootImpl

    Android应用setContentView与LayoutInflater加载解析机制源码分析
    Android窗口机制(二)Window,PhoneWindow,DecorView,setContentView源码理解

    相关文章

      网友评论

      • 994e84007f0c:卖力看进去了还蛮过瘾的
      • 994e84007f0c:“可以看到在这里通过generateLayout()方法将decorView添加到mContentParent中:”这一句改成将mContentParent添加到decorView中比较好……
      • 谁的春春不迷茫:作者你好,我想问下,requestLayout完成异步刷新请求,重绘界面,这句话不怎么明白,这个不是同步的嘛,
      • 夷陵小祖:很棒棒,顶一个
      • 谢谢写:很好,持续关注
      • 掠影天际:讲得非常详细
        Geeks_Liu: @MightyHe 泪奔了,写了这么多博客,终于有回音了~谢谢哈😄

      本文标题:浅谈Activity从建立到显示(setContentView源

      本文链接:https://www.haomeiwen.com/subject/tstvbttx.html