Context 是上下文环境对象,在Android中经常会使用到。
首先Context
是一个抽象类,它常见的子类有:Application、Activity、Service、ContextImpl。这些类关系如下:
说明:
mBase
赋值为ContextImpl
对象ContextWrapper
的核心工作都是交给mBase
(即ContextImpl)来完成的我们通过getApplicationContext()
可以获得一个全局的Context
,那么 Application Context 在什么时候创建的呢?很明显全局的Application Context 是在应用程序启动的时候创建的。
在应用程序的启动过程中,会调用 ActivityThread
的 performLaunchActivity
方法来启动Activity。
1、ActivityThread & performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
return activity;
该方法会调用 r.packageInfo.makeApplication
(即LoadedApk的makeApplication方法) 创建一个Application
对象。查看LoadedApk
的makeApplication
方法:
2、LoadedApk & makeApplication
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
//如果已经创建则直接返回
if (mApplication != null) {
return mApplication;
}
Application app = null;
try {
java.lang.ClassLoader cl = getClassLoader();
...
//创建 ContextImpl
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
//创建 Application
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
...
}
mActivityThread.mAllApplications.add(app);
//赋值
mApplication = app;
...
return app;
该方法会创建一个ContextImpl
对象 appContext 作为newApplication方法胡参数,并调用Instrumentation
的 newApplication
创建 Application 对象。
3、Instrumentation & newApplication
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return newApplication(cl.loadClass(className), context);
}
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
return app;
}
该方法会使用newInstance()获得 Application
的实例,并调用Application
的attach
方法将ContextImpl
传入。
4、Application & attach
/* package */ final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
调用ContextWrapper
的 attachBaseContext
方法
5、ContextWrapper & attachBaseContext
Context mBase;
//mBase 赋值
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
经过层层传递,到这里就完成了Context
的赋值。这里的base
也就是传递的ContextImpl
对象。
我们可以通过getApplicationContext()
获得Application
的Context
对象。
1、ContextWrapper & getApplicationContext()
@Override
public Context getApplicationContext() {
return mBase.getApplicationContext();
}
mBase 是 ContextImpl
的实例。
2、ContextImpl & getApplicationContext()
@Override
public Context getApplicationContext() {
return (mPackageInfo != null) ?
mPackageInfo.getApplication() : mMainThread.getApplication();
}
mPackageInfo
也就是 LoadedApk
对象,由于程序已经启动所以此时mPackageInfo 不为null。执行mPackageInfo.getApplication()
3、LoadedApk & getApplication()
Application getApplication() {
return mApplication;
}
mApplication
在 makeApplication
方法中已经赋值,所以这里就得到了Application 的 Context
Activity 中使用的 Context 会在 Activity 的启动过程中创建。在Activity的启动流程 中我们知道,ActivityThread
会调用 performLaunchActivity
方法来启动一个 Activity。
1、ActivityThread & performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);
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);
...
return activity;
}
createBaseContextForActivity
创建Context对象activity.attach
方法将创建的Context赋值给Activity自己的Context。2、ActivityThread & createBaseContextForActivity
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
...
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.token, displayId, r.overrideConfig);
appContext.setOuterContext(activity);
Context baseContext = appContext;
...
return baseContext;
}
可以看到该方法会创建ContextImpl 对象并返回。
3、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) {
attachBaseContext(context);
...
}
继续调用ContextThemeWrapper
的attachBaseContext
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
}
ContextThemeWrapper 继承 ContextWrapper。
4、ContextWrapper & attachBaseContext
Context mBase;
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
到这里就完成了Activity的Context创建。此时mBase
被赋值就是在上面创建在的ContextImpl对象。
和Activity中Context创建是类似的,Service中Context的创建也是在Service启动过程中创建的。在 Service启动流程 中我们知道在Service启动过程会调用ActivityThread
的 handleCreateService
来启动 Service
1、ActivityThread & handleCreateService
private void handleCreateService(CreateServiceData data) {
...
try {
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();
} catch (Exception e) {
...
}
}
该方法中首先也会创建一个ContextImpl
类型的 context,然后调用service的attach
方法将ContextImpl
类型的context传入。
2、Service & attach
public final void attach(
Context context,
ActivityThread thread, String className, IBinder token,
Application application, Object activityManager) {
attachBaseContext(context);
mThread = thread; // NOTE: unused - remove?
mClassName = className;
mToken = token;
mApplication = application;
mActivityManager = (IActivityManager)activityManager;
mStartCompatibility = getApplicationInfo().targetSdkVersion
< Build.VERSION_CODES.ECLAIR;
}
继续执行attachBaseContext
方法
3、ContextWrapper & attachBaseContext
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
将ContextImpl
类型的Context赋值给mBase
,到此就完成了Service中Context的创建。
参考:《Android进阶解密》