前言
最近打算把 Android 中和 View
相关的知识做一下更新,本来另一篇博客已经写的差不多了,但是发现缺少了这一块关于 Activity
的构成知识的话,在讲述事件分发机制的时候不太好开展,所以这个知识点也就相当于给后面的 View
相关知识做一个补充!废话不多说,我们现在开始。
先下结论
在解析源码之前,我们先把最终的结论得出来,方便我们后面对源码部分进行分析,在我们的 Android 设备上,我们的 Activity
构成应当是这样子的:
如果你之前从未了解过这部分知识,初看可能会觉得相当的陌生。别急,接下来我将为你从外到内介绍这幅图的含义。
- 首先是最外层的
Activity
,每次系统为我们默认建好的MainActivity
,是继承自AppCompatActivity
的,其实AppCompatActivity
也是间接继承自Activity
的一个类,所以我们的最外框层,就是Activity
。 - 接下来是
PhoneWindow
,我们在MainActivity
使用的setContentView
加载布局方法实际上调用的是PhoneWindow
里面的setContentView
方法。 - 然后就到了
DecorView
了,在PhoneWindow
中我们会生成一个DecorView
,而且DecorView
是继承自FrameLayout
的一个类。 - 最后就是
DecorView
里面的TitleView
和ContentView
了,其中TitleView
是用于显示标题的,而ContentView
是我们平时打交道最多的地方,我们写的布局(例如 activity_main.xml)实际上都是放置在这里的,所以这也是我们加载布局的方法要叫做setContentView
而不是直接叫做setView
的一个原因。
好了,讲完了我们 Activity 的构成,我们现在就开始从源码的角度来看看源码是如何构成上面这幅图的吧!
源码解析
首先,我们的布局文件加载都是通过 Activity
的 setContentView
方法加载进来的,也就是说一切的活动从这里开始,那么我们就来看看这个方法里面是什么吧。
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
这里可以看到,代码里面通过 getWindow
调用了 setContentView
方法,getWindow
方法明显是会返回一个对象的,我们就来看看 getWindow
方法的源码是什么。
public Window getWindow() {
return mWindow;
}
这个方法非常的简单,只是简单地返回了一个 mWindow
的变量,这个 mWindow
从前面的定义我们可以得知这是一个 Window
类型的对象,那么它又是从哪里来的呢?
我们接下来把目光聚集到 Activity
的 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,
Window window, ActivityConfigCallback activityConfigCallback) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window, activityConfigCallback); // 1
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());
}
}
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags