上下文Context
基于Android U
Context意为上下文,是一个应用程序环境信息的接口。它的使用场景总的来说分为两大类,分别是:
- 使用Context调用方法,比如启动Activity、访问资源、调用系统服务等。
- 调用方法时传入Context,比如弹出Toast、创建Dialog等。
Activity、Service和Application都间接地继承自Context,因此我们可以计算出一个应用程序进程中有多少个Context,这个数量等于Activity和Service的总个数加1,1指的是Application的数量。
Context是一个抽象类,它的内部定义了很多方法以及静态变量,它的具体实现类为ContextImpl。和Context相关联的类,除了ContextImpl,还有ContextWrapper、ContextThemeWrapper和Activity等。
ContextImpl和ContextWrapper继承自Context,ContextWrapper内部包含Context类型的mBase对象,mBase具体指向ContextImpl。ContextImpl提供了很多功能,但是外界需要使用并拓展ContextImpl的功能,因此设计上使用了装饰模式,ContextWrapper是装饰类,它对ContextImpl进行包装,ContextWrapper主要是起了方法传递的作用,ContextWrapper中几乎所有的方法都是调用ContextImpl的相应方法来实现的。ContextThemeWrapper、Service和Application都继承自ContextWrapper,这样它们都可以通过mBase来使用Context的方法,同时它们也是装饰类,在ContextWrapper的基础上又添加了不同的功能。ContextThemeWrapper中包含和主题相关的方法(比如getTheme方法),因此需要主题的Activity继承ContextThemeWrapper,而不需要主题的Service继承ContextWrapper。
Context的关联类采用了装饰模式,主要有以下的优点:
- 使用者(比如Service)能够更方便地使用Context。
- 如果ContextImpl发生了变化,它的装饰者ContextWrapper不需要做任何修改。
- ContextImpl的实现不会暴露给使用者,使用者也不必关心ContextImpl的实现。
- 通过组合而非继承的方式,拓展ContextImpl的功能,在运行时选择不同的装饰者,实现不同的功能。
Application Context的创建过程

我们通过调用getApplicationContext来获取应用程序全局的Application Context,那么Application Context是如何创建的呢?在一个应用程序启动完成后,应用程序就会有一个全局的Application Context,那么我们就从应用程序启动过程开始着手。
从ActivityThread的performLaunchActivity()方法开始(前面的调用部分可以看《根Activity的启动过程》)。
1 | |
注释1处创建Activity实例,这里的Activity指的是我们要启动的新的XXXActivity。调用了Instrumentation类的newActivity()方法;
注释2处尝试创建Application,r.packageInfo返回的是LoadedApk对象,调用了LoadedApk的makeApplicationInner()方法。
注释3处创建Activity的PhoneWindow,并将当前线程设置成主线程。我们在这个fork出来的新进程中还没有创建其他线程,这个Activity也是该App启动的第一个Activity,所以这个Activity就是在主线程中运行的。
注释4处调用了Instrumentation的callActivityOnCreate(),执行新Activity的onCreate生命周期。
1 | |
注释1处如果mApplication不为null则返回mApplication,这里假设是第一次启动应用程序,因此mApplication为null。
注释2处通过ContextImpl的createAppContext()方法来创建ContextImpl。
注释3处创建Application,在Instrumentation的newApplication()方法中传入了ClassLoader类型的对象以及注释2处创建的ContextImpl。
注释4处将Application赋值给ContextImpl的Context类型的成员变量mOuterContext,这样ContextImpl中也包含了Application的引用。
注释5处将Application赋值给LoadedApk的成员变量mApplication,这个mApplication是Application类型的对象,它用来代表Application Context。
1 | |
注释1处通过反射来创建Application,注释2处调用了Application的attach()方法,将ContextImpl传进去,最后返回该Application。
1 | |
调用attachBaseContext(),它在Application的父类ContextWrapper中实现。
1 | |
这个base一路传递过来指的是ContextImpl,它是Context的实现类,将ContextImpl赋值给ContextWrapper的Context类型的成员变量mBase,这样在ContextWrapper中就可以使用Context的方法,而Application继承自ContextWrapper,同样可以使用Context的方法。Application的attach()方法的作用就是使Application可以使用Context的方法,这样Application才可以用来代表Application Context。
Application Context的获取过程
我们通过调用getApplicationContext()方法来获得Application Context,getApplicationContext()方法在ContextWrapper中实现。
1 | |
mBase指的是ContextImpl。
1 | |
如果LoadedApk类型的mPackageInfo不为null,则调用LoadedApk的getApplication()方法,否则调用ActivityThread的getApplication()方法。由于应用程序这时已经启动,因此LoadedApk不会为null。
1 | |
这里的mApplication在上文LoadedApk的makeApplication()方法的注释5处被赋值。这样我们通过getApplication()方法就获取到了Application Context。
Activity的Context创建过程

想要在Activity中使用Context提供的方法,务必要先创建Context。Activity的Context会在Activity的启动过程中被创建。
从ActivityThread的performLaunchActivity()方法开始(前面的调用部分可以看《根Activity的启动过程》)。
1 | |
注释2处用来创建Activity的实例。
注释1处通过createBaseContextForActivity()方法来创建Activity的ContextImpl,并将ContextImpl传入注释4处的activity的attach()方法中。
注释3处调用了ContextImpl的setOuterContext()方法,将此前创建的Acitivity实例赋值给ContextImpl的成员变量mOuterContext,这样ContextImpl也可以访问Activity的变量和方法。
注释5处mInstrumentation的callActivityOnCreate()方法中会调用Activity的onCreate()方法。
createBaseContextForActivity()
1
2
3
4
5
6
7
8frameworks/base/core/java/android/app/ActivityThread.java
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
...
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
...
return appContext;
}在createBaseContextForActivity()中会调用ContextImpl的createActivityContext()方法来创建ContextImpl。
activity.attach()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30frameworks/base/core/java/android/app/Activity.java
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, IBinder assistToken,
IBinder shareableActivityToken) {
attachBaseContext(context); // 1
mFragments.attachHost(null /*parent*/);
mActivityInfo = info;
mWindow = new PhoneWindow(this, window, activityConfigCallback); // 2
mWindow.setWindowControllerCallback(mWindowControllerCallback);
mWindow.setCallback(this); // 3
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
...
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0); // 4
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager(); // 5
...
}在注释2处创建PhoneWindow,它代表应用程序窗口。PhoneWindow在运行中会间接触发很多事件,比如点击、菜单弹出、屏幕焦点变化等事件,这些事件需要转发给与PhoneWindow关联的Activity,转发操作通过Window.Callback接口实现,Activity实现了这个接口。在注释3处将当前Activity通过Window的setCallback()方法传递给PhoneWindow。在注释4处为PhoneWindow设置WindowManager,在注释5处获取WindowManager并赋值给Activity的成员变量mWindowManager,这样在Activity中就可以通过getWindowManager()方法来获取WindowManager。
注释1处的attachBaseContext()方法在ContextThemeWrapper中实现。
1
2
3
4frameworks/base/core/java/android/view/ContextThemeWrapper.java
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
}attachBaseContext()调用ContextThemeWrapper父类ContextWrapper的attachBaseContext()方法。
1
2
3
4
5
6
7frameworks/base/core/java/android/content/ContextWrapper.java
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base; // 1
}注释1处的base指的是一路传递过来的Activity的ContextImpl,将它赋值给ContextWrapper的成员变量mBase。这样ContextWrapper的功能就可以交由ContextImpl来处理。举个例子,如下:
1
2
3
4frameworks/base/core/java/android/content/ContextWrapper.java
public Resources.Theme getTheme() {
return mBase.getTheme();
}当我们调用ContextWrapper的getTheme()方法时,其实就是调用了ContextImpl的getTheme()方法。
总结:在启动Activity的过程中创建ContextImpl,并赋值给ContextWrapper的成员变量mBase。Activity继承自ContextWrapper的子类ContextThemeWrapper,这样在Activity中就可以使用Context中定义的方法了。
Service的Context创建过程
Service的Context创建过程与Activity的Context创建过程类似,是在Service的启动过程中被创建的。
我们从ActivityThread的handleCreateService()开始分析。
handleMessage()方法根据消息类型为CREATE_SERVICE,会调用handleCreateService()方法。
1 | |
注释1处通过ContextImpl的createServiceBaseContext()方法创建了ContextImpl,并将该ContextImpl传入注释2处service的attach()方法中。
1 | |
注释1处调用了attachBaseContext()。
1 | |
注释1处调用了ContextWrapper的attachBaseContext()。
1 | |
注释1处的base指的是一路传递过来的Service的ContextImpl,将它赋值给ContextWrapper的成员变量mBase。这样在ContextWrapper中就可以使用Context的方法,而Service继承自ContextWrapper,同样可以使用Context的方法。