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

准备工作

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

image.png

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

image.png

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

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 :

image.png

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

添加视图

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

image.png

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

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方法

image.png

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

image.png

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

1

image.png

利用WindowManager讲DecorView添加到Window

2

image.png

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

总结

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容