序言
很多人都会用Activity、Window、View,但是你知道他们是怎样加载出来并呈现在你眼前的吗?你知道他们之间有着鲜为人知的关系吗?
讲个很简单的例子,这一天天气甚好,小明外出写生,小明背了一包东西,画板啊,纸啊,笔啊什么的,然后小明找了一处风景甚好的地方,从包里拿出画板,纸,笔然后开始画画,不一会儿小明就画完了一幅风景图。在这个例子当中,画板就好比Activity,纸就好比Window,而笔就是View,我们所看到的就是这幅画,是通过笔一点一点画出来的,在哪里画呢?当然是纸上了,而最终承载这幅画的东西就是画板了。这么说可能不太生动,下面,我们从源码的角度来看看这三者的关系。
Activity的创建过程
我们都知道,Activity启动的时候是从ActivityThread中的Handler中发起的,然后经过handlerLauncher等一系列方法,如果还不知道的话可以去参考我之前写的:
1ActivityThread类:
2
3private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
4
5 ...
6 WindowManagerGlobal.initialize();
7 Activity a = performLaunchActivity(r, customIntent);
8 ...
9}
在这里先调用了WindowManagerGlobal
中的初始化方法初始化了WindowManagerService
,看名字大概就能知道这是一个WindowManager
的服务,通过这个服务可以对页面进行操作;然后通过调用performLaunchActivity
方法生成了一个Activity。
Window的创建过程
上面通过performLaunchActivity
方法生成了一个Activity,我们来看看是怎样生成的:
1ActivityThread类:
2
3private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
4
5 ...
6 Activity activity = null;
7 try {
8 activity = mInstrumentation.newActivity(cl,
9 component.getClassName(), r.intent);
10 } catch (Exception e) {
11 ...
12 }
13 ...
14
15 if (activity != null) {
16 activity.attach(appContext, this, getInstrumentation(), r.token,
17 r.ident, app, r.intent, r.activityInfo, title, r.parent,
18 r.embeddedID, r.lastNonConfigurationInstances, config,
19 r.referrer, r.voiceInteractor, window, r.configCallback);
20 }
21
22 ...
23}
在这个方法中,通过newActivity
这个方法(反射)来生成了一个Activity
,生成好了Activity
之后就调用Activity
中的attach
方法,来看一下这个方法里面干了些什么:
1final void attach(Context context, ActivityThread aThread,
2 Instrumentation instr, IBinder token, int ident,
3 Application application, Intent intent, ActivityInfo info,
4 CharSequence title, Activity parent, String id,
5 NonConfigurationInstances lastNonConfigurationInstances,
6 Configuration config, String referrer, IVoiceInteractor voiceInteractor,
7 Window window, ActivityConfigCallback activityConfigCallback) {
8
9 mWindow = new PhoneWindow(this, window, activityConfigCallback);
10 mWindow.setWindowControllerCallback(this);
11 mWindow.setCallback(this);
12 mWindow.setOnWindowDismissedCallback(this);
13 mWindow.getLayoutInflater().setPrivateFactory(this);
14 if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
15 mWindow.setSoftInputMode(info.softInputMode);
16 }
17 if (info.uiOptions != 0) {
18 mWindow.setUiOptions(info.uiOptions);
19 }
20}
果然,在Activity
的attach
方法中创建了一个Window
,这个Window
就是我们经常听到的PhoneWindow
View的创建过程
我们大胆的猜测一下,View
应该是被添加到Window
中的,那么我们来看一下,到底是怎样添加的呢?上面说到在handlerLauncher
中调用了performLaunchActivity
方法,源码中还调用了handleResumeActivity
方法,这个方法是在生命周期onCreate
之后,onResume
之前调用的,我们来看一下在这个方法中干了些什么:
1final void handleResumeActivity(IBinder token,
2 boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
3
4 ...
5 r = performResumeActivity(token, clearHide, reason);
6 ...
7 if (r.window == null && !a.mFinished && willBeVisible) {
8 r.window = r.activity.getWindow();
9 View decor = r.window.getDecorView();
10 decor.setVisibility(View.INVISIBLE);
11 ViewManager wm = a.getWindowManager();
12 WindowManager.LayoutParams l = r.window.getAttributes();
13 a.mDecor = decor;
14
15 ...
16 wm.addView(decor, l);
17 ...
18 }
19}
这里会先获取一个Window
和DecorView
,然后拿到ViewManager
(WindowManager
的父类),然后调用addView
方法,ViewManager
和WindowManager
都是接口,那么我们只要到他的实现类WindowManagerImpl
中去找addView
方法就可以了:
1 @Override
2 public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
3 applyDefaultToken(params);
4 mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
5 }
这个mGlobal
就是我们之前的WindowManagerGlobal
,看到这里相信大家应该有点眉目了吧,最终是由这货负责把DecorView
添加到Window中,在WindowManagerGlobal
中的addView
方法中还会初始化ViewRootImpl
,有兴趣的可以自行看源码了解一下XML
中的View
是如何添加到DecorView
中的这个也不在这里分析了,可以参考我之前写的:
总结
啥也不说了,上图
作者:24K纯帅豆