理解上下文 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 的创建过程
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);
}
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;
}
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;
}
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance(); // ... 1
app.attach(context); // ... 2
return app;
}
/* package */ final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
在attach方法中调用了attachBaseContext方法,它在Application的父类ContextWrapper中实现,代码如下所示:
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
3. Application Context 的获取过程
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();
}
Application getApplication() {
return mApplication;
}
4. Activity的Context 创建过程
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);
}
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;
}
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
...
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
...
return appContext;
}
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 /*parent*/);
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);
}
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
}
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base; // ... 1
}
5. Service的Context 创建过程
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);
}
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);
}
}
}
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;
}
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base; // ... 1
}