理解上下文 Context
Context 也就是上下文对象,是 Android 常用的类,但是对于 Context ,很多人都停留在会用的阶段,本文将带领大家从源码的角度来分析 Context ,从而更加深入地理解它。 本文基于Android8.1.0系统分析Context。1. Context 的关联类
Context 意为上下文,是一个应用程序环境信息的接口。
在开发中我们经常使用 Context ,它的使用场景总的来说分为两大类,它们分别是:
- 使用 Context 调用方怯,比如启动 Activity 、访问资糖、调用系统级服务等。
- 调用方怯时传入 Context 比如弹出 Toast 、创建 Dialog 等。
从上图可以看出,Contextlmpl 和 ContextWrapper 继承自 Context,ContextWrapper 内部包含 Context 类型的 mBase 对象, mBase 具体指向 Contextlmpl。Contextlmpl 提供了很多功能,但是外界需要使用并拓展 Contextlmpl 的功能,因此设计上使用了装饰模式, ContextWrapper 是装饰类,它对 Contextlmpl 进行包装, ContextWrapper主要是起了方法传递的作用, ContextWrapper 中几乎所有的方法都是调用 Contextlmpl 的相应方法来实现的。 ContextThemeWrapper、Service、Application 都继承自 ContextWrapper,这样它们都可以通过 mBase 来使用 Context 的方法,同时它们也是装饰类,在 ContextWrapper的基础上又添加了不同的功能。 ContextThemeWrapper 中包含和主题相关的方法(比如getTheme 方法),因此,需要主题的 Activity 继承 ContextThemeWrapper ,而不需要主题的Service 继承 ContextWrapper。
Context 的关联类采用了装饰者模式,主要有以下的优点:
- 使用者(比如 Service )能够更方便地使用 Context。
- 如果 Contextlmpl 发生了变化,它的装饰类 ContextWrapper 不需要做任何修改。
- Contextlmpl 的实现不会暴露给使用者,使用者也不必关心 Contextlmpl 的实现。
- 通过组合而非继承的方式,拓展 Contextlmpl 功能,在运行时选择不同的装饰类, 实现不同的功能
2. Application Context 的创建过程
我们通过调用 getApplicationContext 来获取应用程序全局的 Application Context ,那么 Application Context 是如何创建的呢?在一 个应用程序启动完成后,应用程序就会有一 个全局的 Application Context ,那么我们就从应用程序启动过程开始着手。 ActivityThread 类作为应用程序进程的 主线程管理类 ,它 会调 用它的内部类 A pplication Thread 的 scheduleLaunchActivity 方法来启动 Activity ,如下所示:frameworks/base/core/java/android/app/ActivityThread.java
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}
在Application
Thread 的
scheduleLaunchActivity 方法
中向 H
类发送
LAUNCH_AC
TIVITY
类型的消息,目的是将启动 Acti
vity
的逻辑放在主线程的消息队列中,这样启动
Ac
tivity 的
逻辑会在主线程中执行。我们接
着查看 H
类的
handleMessage
方法对
LAUNCH_
ACTMTY
类型
的消息的处理,代码如下所示:
frameworks/base/core/java/android/app/ActivityThread.java
private class H extends Handler {
...
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj; // ... 1
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo); // ... 2
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY"); // ... 3
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
...
}
Object obj = msg.obj;
if (obj instanceof SomeArgs) {
((SomeArgs) obj).recycle();
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
}
H继承自Handler,在注释1处将传过来的 msg 的成员变量 obj 转换为 ActivityClientRecord 。在注释2处通过 getPackagelnfoNoCheck 方法获得 LoadedApk 类型的对象并赋值给 ActivityClientRecord 的成员变量packagelnfo 。应用程序进程要启动 Activity 需要将该 Activity 所属的 APK 加载进来,而 LoadedApk 就是用来描述己加载的 APK 文件的。在注释3处调用 handleLaunchActivity 方法,代码如下所示:
frameworks/base/core/java/android/app/ActivityThread.java
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
...
// 启动Activity
Activity a = performLaunchActivity(r, customIntent); // ... 1
...
}
在handleLaunchActivity 方法中调用了 ActivityThread 的 performLaunchActivity 方法,代码如下所示:
frameworks/base/core/java/android/app/ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
try {
// 创建Application
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
}
...
return activity;
}
在performLaunchActivity 方法
中有很
多重要
的逻
辑,这里只保留了和
Application
Context 相关的逻辑,想要了解更多
perfomL
aunchActivity 方法中的逻辑请查看“解析Activity的启动过程
”的
内容。 ActivityClientRecord
的成员变
packagelnfo 是
LoadedApk
类型的,我
们接
着来查看
LoadedApk 的 makeApplication 方法
,代码如下所示:
frameworks/base/core/java/android/app/LoadedApk.java
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) { // ... 1
return mApplication;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
Application app = null;
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}
try {
java.lang.ClassLoader cl = getClassLoader();
if (!mPackageName.equals("android")) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"initializeJavaContextClassLoader");
initializeJavaContextClassLoader();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); // ... 2
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext); // ... 3
appContext.setOuterContext(app); // ... 4
} catch (Exception e) {
if (!mActivityThread.mInstrumentation.onException(app, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Unable to instantiate application " + appClass
+ ": " + e.toString(), e);
}
}
mActivityThread.mAllApplications.add(app);
mApplication = app; // ... 5
...
return app;
}
在注释1
处如果
mApplication
不为
null
则返回
mApplication
,这里假设是第一
次启动
应用程序,因此 mApp
lication 为
null
。在注释2
处通过
Con
textlmpl 的
createAppContext 方法
来创建 Contextlmpl
。注释3
处的代码用来创建
Application
,在
Instrumentation 的
new
Application
方怯中传入了
ClassLoader
类型的对象以及注释2
处创建的
Contextlmpl
。在注释4处将 Application
贼值给
Contextlmpl 的
Context
类型的成员变量
mOuterContext
,这 样
Contextlmpl 中也包含了
Application
的引用。
在注释5处将
Application
赋值给
LoadedApk 的成员变 mApplication
,这个
mApplication 是
Application
类型的对象,它用来代表 Application Context
,在
Application
Context
的获取过程中我们会再次提到
mApplication
。下面来
查看
注释3
处的
Application
是如何创建的,
Instrumentation 的
new
Application 方法代码
如下所示:
frameworks/base/core/java/android/app/lnstrumentation.java
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance(); // ... 1
app.attach(context); // ... 2
return app;
}
Instrumentation
中有两个
new
Application
重载方法,最终会调
用上面这个重载方法。注释1
处通过反射来创 Application
,在注释2处调用了
Application 的
attach 方法,
将
Contextimpl 传进去,
最后
返回该
Application ,
Application 的
attach
方法如下所示:
frameworks/base/core/java/android/app/Application.java
final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
在attach方法中调用了attachBaseContext方法,它在Application的父类ContextWrapper中实现,代码如下所示:
frameworks/base/core/java/android/content/ContextWrapper.java
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
这个
base
一路传递过来指的是
Contextimpl
,它是
Context
的实现
类,
Contextimpl 赋值给 Context
Wrapper 的
Context
类型的成员变
mBase
,这样在
Context
Wrapper
中就可以使用 Context
的方法,而
Application
继承自
Context
Wrapper
,同样可以使用
Context
的方法。 Application 的
attach 方法
的作用就是使
Application
可以使用
Context
的方法,这样 Application 才可以用来代表
Application
Context。
Application
Context
的创建过程就讲到这里,接下来
我们
来分析A
pplication
Context 的
获取过程。
3. Application Context 的获取过程
当我们熟知了 Application Context 的创建过程之后,那么它的获取过程会非常好理解。 我们通过调用 getApplicationContext 方法来获得 Application Context, getApplicationContext 方法在 Context Wrapper 中实现,代码如下所示: frameworks/base/core/java/android/content/ContextWrapper.java
public Context getApplicationContext() {
return mBase.getApplicationContext();
}
在getApplicationContext 方法中,mBase指的是ContextImpl,接下来查看ContextImpl的getApplicationContext 方法,代码如下所示:
frameworks/base/core/java/android/app/Contextlmpl.java
public Context getApplicationContext() {
return (mPackageInfo != null) ?
mPackageInfo.getApplication() : mMainThread.getApplication();
}
如果
LoadedApk
类型的
mPackagelnfo
不为
null
,则调用
LoadedApk 的
getApplication 方法,否则调用 ActivityThread 的
getApplication 方法
。由于应用程序这时已经启动,因此 LoadedApk不会为
null
,则
会调用
LoadedApk 的
getApplication 方法
,代码如下所示:
frameworks/base/core/java/android/app/LoadedApk.java
Application getApplication() {
return mApplication;
}
这里的
mApplication
我们应该很熟悉,它在上文
LoadedApk 的
makeApplication 方法
的
注释5处被赋值。这样我们通过
getAppl
icationContext 方法
就获取到了
Application
Context 。
4. Activity的Context 创建过程
想要在 Activity 中使用 Context 提供的方法,务必要先创建 Context 。 Activity 的 Context 会在 Activity 的启动过程中被创建,在 “解析Activity的启动过程 ”中讲到了 ActivityThread 启动 Activity 的过程,我们就从这里开始分析。 ActivityThread 类作为应用程序进程的 主线程管理类 ,它 会调 用它的内部类 A pplication Thread 的 scheduleLaunchActivity 方法来启动 Activity ,如下所示:frameworks/base/core/java/android/app/ActivityThread.java
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}
scheduleLaunchActivity
方法将启动
Activity
的参数封装成 ActivityClientRecord
, sendMessage
方法向 H
类发
送类型为
LAUNCH_
ACTIVITY
的消
息,
并将
ActivityC
lientR
ecord 传递过去。 sendMessage 方法
的目的是将启动
Activity
的逻辑放
在主
线程的消息队列中,这样启动 Activity 的逻辑就会
在主线
程中执行 。H 类的 h
and
leMessage
方法会对
LAUNCH_ACTIVITY 类型的消息进行处理,其中调用了
Activity
Thr
ead 的 ha
ndl
eLaunchActi
vity 方法,而在
handleLaunchActivity
方法中又
调用了
ActivityThread 的
perfomLa
un
chActi
vity
方法,这一过程在第2
节已经
讲过了,我们直
接来
查看
ActivityThread 的
perforrnLau
nchActi
vity 方法,代码如下所示:
frameworks/base/core/java/android/app/ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
ContextImpl appContext = createBaseContextForActivity(r); // ... 1
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent); // ... 2
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
...
}
try {
...
if (activity != null) {
...
appContext.setOuterContext(activity); // ... 3
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, r.configCallback); // ... 4
...
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); // ... 5
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
}
r.paused = true;
mActivities.put(r.token, r);
} 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;
}
在 perfomLaunchActivity
方法中有很多重
要的逻辑,这里
只保留了和
Activity 的
Context 相关
的逻辑 。
在注释2
处用来创建
Activity
的实例,
在注释1
处通过 createBaseContextForActivity 方法来创建 Activity 的
Contextlmpl ,并将 Contextlmpl
传入
注释 4
处的
activity 的
attach 方法中。在注释3处调用了
Contextlmpl 的
setOuterContext 方法
,将此前创建的
Activity
实例赋值给 Contextlmpl
的成员变
mOuterContext
,这样
Contextlmpl
也可以访问
Activity
的变量
和方法
。在
注释5
处 m
Instrumentation 的
callActivityOnCre
ate 方法中会
调用
Activity 的
onCreate
方法。我们
查看
注释1
处的 createBaseContextForActivity 方法,代码如下所示:
frameworks/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 方法中会调用
Contextlmpl 的
createActivityContext 方法来创建 Contextlmpl 。
我们回到
ActivityThread 的
perforrnLau
nchActi
vity 方法
,
查看
注释4
处的 Activity 的
attach 方法
,代码如下所示:
frameworks/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) {
attachBaseContext(context); // ... 1
mFragments.attachHost(null );
mWindow = new PhoneWindow(this, window, activityConfigCallback); // ... 2
mWindow.setWindowControllerCallback(this);
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
mCurrentConfig = config;
mWindow.setColorMode(info.colorMode);
}
在注释2处创建
Phone
Window ,
它代表应用程
序窗
口。
Phone
Window 在
运行中会
间接触发很
多事
件,比如点击、菜
单弹出、屏幕
焦点变化等事件,这些事件要转发给与 PhoneWindow
关联的 Activity
,转发操作通过
Window.
Callback
接口实现,
Actvity
实现了这个接口
。在注释3
处将当前
Activity 通过
Window 的
setCallback 方法
传递给
Phone
Window 。在注释4处为
Phone
Window 设置 Window
Manager
,在注释5
处获取
Window
Manager 并
赋值 Activity 的成员变 m
Window
Manager
,这样在
Activity
中就可以通过
get
Window
Manager 方法来获取 Window
Manager
。注释1
处的
attachBaseContext 方法
在
ContextTheme
Wrapper 中实现,代码如下所示:
frameworks/base/core/java/android/view/ContextThemeWrappe.java
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
}
在attachBaseContext 方法中接着
调用 ContextThemeWrapper 的父类 ContextWrapper 的 attachBaseContext 方法,代码如下所示:
frameworks/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 的
Contextlmpl
,将它赋值给 ContextWrapper
的成员变
mBase
。这样
ContextWrapper
的功能就可以交由
Contextlmpl
来处理。
Activ
ity 的
Conte
xt
创建过程就讲到这里。总结一
下,在启动
Activity
的过程中创建
Contextlmpl
,并赋值给
Context
Wrapper
的成员变
mBase 。
Activity
继承自
Context
Wrapper
的子类
ContextTheme
Wrapper
,这样在 A
ctivity
中就可以使用
Context 中
定义的方法了。
5. Service的Context 创建过程
Service 的 Context 创建过程与 Activity 的 Context 创建过 程类 似, 是在 Service 的启动过程中被创建的。在 “解析Service的启动过程 ”中讲到了 Activi tyThread 启动 Service 的过程,我们从这里开始分析。 ActivityThread 的内部类 Application Thread 调用 scheduleCreateService 方法 来 启动 Service,代码如下所示: frameworks/base/core/java/android/app/ActivityThread.java
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
sendMessage
方法向 H 类
发送
CREATE_
SERVICE
类型
的消息, H
类的
ha
ndl
eMessage 方法会对 CREATE_
SERVICE 类型的消息进行处理,其中调用了
ActivityThread 的 handleCreateService
方法,代码如下所示:
frameworks/base/core/java/android/app/ActivityThread.java
private void handleCreateService(CreateServiceData data) {
...
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
// 创建Service的上下文环境ContextImpl对象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo); // ... 1
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
// 初始化Service
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService()); // ... 2
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
在注释1处通过ContextImpl 的
createAppContext 方法
创建了 ContextImpl 的对象context
,并将该context对象传
入注释2处 service 的 attach
方法中,代码如下所示
:
frameworks/base/core/java/android/app/Service.java
public final void attach(
Context context,
ActivityThread thread, String className, IBinder token,
Application application, Object activityManager) {
attachBaseContext(context); // ... 1
mThread = thread; // NOTE: unused - remove?
mClassName = className;
mToken = token;
mApplication = application;
mActivityManager = (IActivityManager)activityManager;
mStartCompatibility = getApplicationInfo().targetSdkVersion
< Build.VERSION_CODES.ECLAIR;
}
在注释1
处调用了
Context
Wrapper
的 attachBaseContext 方法
,代码如下所示:
frameworks/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是
一路传递过来的
Contextimpl
,将
Contextlmpl
赋值给
Context
Wrapper 的 Context 类型的成员变
mBase ,
这样在
Context
Wrapper
中就可以使用
Context
的方法
,
Service 继承自
Context
Wrapper
,同样可以使用
Context
的方法。