源码分析Activity启动Window的创建、添加、显示过程

准备工作

分析源码前,为了方便在Android Studio查看源码,打开网址:https://github.com/anggrayudi/android-hidden-api下载对应的API源码

源码分析Activity启动Window的创建、添加、显示过程_第1张图片
image.png

然后将下载的源码,替换自己SDK下对应PAI的android.jar

源码分析Activity启动Window的创建、添加、显示过程_第2张图片
image.png

然后重启Android Studio之后查看android.jar后就可以查看源码

源码分析Activity启动Window的创建、添加、显示过程_第3张图片
image.png

Activity启动

应用程序的入口类是ActivityThread,在ActivityThread中有performLaunchActivity来启动Activity,这个performLaunchActivity方法内部会创建一个Activity。下面查看performLaunchActivity方法:

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
           ····省略代码
        Activity activity = null;
        try {
            //反射创建一个Activity
            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 {
                ····省略代码
                //创建PhoneWindow和WindowManager

                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window);

                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()) {

                  //调用Activity的onCreate方法
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }

           ····省略代码

        } 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;
    }

attach方法创建PhoneWindow和WindowManager

跟随attach方法来到Activity里面查看:

    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,
            Window window) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);
        //创建PhoneWindow
        mWindow = new PhoneWindow(this, window);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
            mWindow.setSoftInputMode(info.softInputMode);
        }
        if (info.uiOptions != 0) {
            mWindow.setUiOptions(info.uiOptions);
        }
        mUiThread = Thread.currentThread();

        mMainThread = aThread;
        mInstrumentation = instr;
        mToken = token;
        mIdent = ident;
        mApplication = application;
        mIntent = intent;
        mReferrer = referrer;
        mComponent = intent.getComponent();
        mActivityInfo = info;
        mTitle = title;
        mParent = parent;
        mEmbeddedID = id;
        mLastNonConfigurationInstances = lastNonConfigurationInstances;
        if (voiceInteractor != null) {
            if (lastNonConfigurationInstances != null) {
                mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
            } else {
                mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
                        Looper.myLooper());
            }
        }
      //设置WindowManager
        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;
    }

上面代码里有两处很重要,第一个就是创建PhoneWindow,PhoneWindow是继承Window的,PhoneWindow就是后面用于显示的载体,因为要在PhoneWindow上添加,删除,更新VIew都要通过WindowManager来操作,所以看看PhoneWindow里的setWindowManager方法,很遗憾,这个方法在父类Window里面:

 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);
        }
        //WindowManagerImpl里创建WindowManager 
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

上面的代码里WindowManagerImpl是WindowManager 的实现类,去查看createLocalWindowManager方法创建WindowManager :

源码分析Activity启动Window的创建、添加、显示过程_第4张图片
image.png

这样一来PhoneWindow就持有了WindowManager ,就可以操作view了.既然PhoneWindow也已经创建WindowManager 也有了,下面看如何添加视图.

添加视图

在ActivityThread中performLaunchActivity,方法中调用Activity的onCreate方法

源码分析Activity启动Window的创建、添加、显示过程_第5张图片
image.png

Activity的onCreate中的setContentView方法跟随进去查看:

源码分析Activity启动Window的创建、添加、显示过程_第6张图片
image.png

可知getWindow就是刚刚创建的PhoneWindow,跟随PhoneWindow查看setContentView


   @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) {
        //1.创建DecorView,以及DecorView中的mContentParent 布局
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {  
          //2,将layoutResID布局加载到mContentParent和上
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
        //3通知视图改变回调
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

在上面代码1中进去查看PhoneWindow中installDecor方法

源码分析Activity启动Window的创建、添加、显示过程_第7张图片
image.png

可以看到1是创建DecorView,2是通过findviewById找到DecorView中的mContentParent并创建,如此一来,布局文件加载到了DecorView上面,接下来就是显示了,在显示之前发现WindowManager并没有添加到Window上

源码分析Activity启动Window的创建、添加、显示过程_第8张图片
image.png

上面代码在handleLaunchActivity中1performLaunchActivity是创建Activity,2则是要将view添加到Window
上并显示,在handleResumeActivity中有如下方法:

1

源码分析Activity启动Window的创建、添加、显示过程_第9张图片
image.png

利用WindowManager讲DecorView添加到Window

2

源码分析Activity启动Window的创建、添加、显示过程_第10张图片
image.png

显示视图,这样view的添加和显示都清晰了.

总结

文章写得只是大致流程,没有具体到每个细节,也可能有的地方描述不正确,谢谢指出,大家一起进步.

你可能感兴趣的:(源码分析Activity启动Window的创建、添加、显示过程)