各种Context及其初始化流程
Context在Android开发中实在是太重要的,用到的地方数不胜数。开发过程中没有Context是万万不能的,给人感觉Context简直是“万能”的。因为总有一些地方会用到Context,可以通过传参的方式传入;但是有些又没法通过传参传入,这时候可以使用全局ApplicationContext的方式获取到一个Context(见《如何获取全局Context?》)。总的来说有两种用法:
①调用Context的方法。比如startActivity()、getSystemService()、bindService()等等
②当做参数传给需要的构造函数或者方法。比如new Dialog(this)、LayoutInflater.from(context)等等
1、Context簇
在开发过程中,大部分场景总能随时随地的拿到Context使用,而且Context中封装了非常多的方法和常量直接使用,这一点非常方便。得益于Context类族有较好的设计。
Context本身是抽象类,直接实现有两个:ContextImpl和ContextWrapper。ContextImpl是Context的实现类。ContextWrapper内部成员变量mBase初始化后其实就是ContextImpl。ContextWrapper对Context类进行包装(装饰模式),真正的实现还是通过mBase调用ContextImpl中实现的方法。
四大组件中两个有生命周期的组件:Activity、Service都直接或间接继承了ContextWrapper。Service是“虚无”的,肉眼看不见,不需要主题,直接继承自ContextWrapper。而Activity因为有主题有所不同,所以又由ContextThemeWrapper继承自ContextWrapper封装了一层。
2、Application Context
一个应用的全局Application Context是如何被创建并初始化的呢?上回说到Activity的启动流程(参考《Activity启动流程源码分析》),走到ActivityThread的performLaunchActivity(...)方法中:
/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
} catch (Exception e) {
}
return activity;
}ActivityClientRecord是ActivityThread的静态内部类,其中packageInfo成员是LoadedApk类型。makeApplication(...)方法:
public Application makeApplication(boolean ,Instrumentation ) {
if (mApplication != null) {
return mApplication;
}
Application app = null;
...
try {
java.lang.ClassLoader cl = getClassLoader();
...
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
...
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
...
return app;
}方法中调用ContextImpl的createAppContext(ActivityThread mainThread, LoadedApk packageInfo)方法创建ContextImpl对象
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
return createAppContext(mainThread, packageInfo, null);
}
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo,
String opPackageName) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
null, opPackageName);
context.setResources(packageInfo.getResources());
return context;
}再通过Instrumentation的newApplication(...)创建构造Application对象
/**
* 执行流程的{@link Application}对象的实例化。 默认实现提供正常的系统行为。
*/
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
app.attach(context);
return app;
}其中调用Application的attach(Context )方法
/* package */ final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}将传入的ContextImpl对象设置给当前Application中的成员变量mBase。
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}别忘了,Application类继承自ContextWrapper,attachBaseContext(Context base)定义在父类ContextWrapper中。至此,Application的Context初始化完成,可以在Application中使用Context。
3、Activity Context
继续Activity的启动流程(参考《Activity启动流程源码分析》),同样是走到ActivityThread的performLaunchActivity(...)方法,这次关注的代码段和Application Context创建不一样不一样:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
}
...
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
if (activity != null) {
...
appContext.setOuterContext(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, r.configCallback,
r.assistToken);
...
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
}
...
}
...
return activity;
}方法中有几个关键的地方:
首先,调用本地方法createBaseContextForActivity()创建ContextImpl类型的变量appContext:
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
...
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
...
return appContext;
}其次,通过Instrumentation类的newActivity(ClassLoader cl, String className,Intent intent)方法load创建activity。
再调用ContextImpl的setOuterContext(Context context)方法,将创建的activity传给ContextImpl类中的mOuterContext成员变量,这样ContextImpl也就反过来持有Activity,可以访问Activity成员。
final void setOuterContext(Context context) {
mOuterContext = context;
}最后关键的一步,来看调用了Activity的attach(...)方法,将ContextImpl赋值给Activity父类中的mBase,以及进行一系列配置变量的初始化。
final void attach(Context context, ...) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window, activityConfigCallback);
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;
mAssistToken = assistToken;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
...
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
mWindow.setColorMode(info.colorMode);
...
}方法中其它的都先不管,看第一行,调用了Activity中的attachBaseContext(context)方法
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
if (newBase != null) {
newBase.setAutofillClient(this);
newBase.setContentCaptureOptions(getContentCaptureOptions());
}
}然后调用了父类ContextThemeWrapper的attachBaseContext(context)方法
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
}最后调用ContextWrapper中的attachBaseContext(context)方法,完成mBase成员变量的初始化,所有的Context实现都有mBase类也就是ContextImpl来实现,ContextWrapper当做中间件。
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}到这里,完成了Activity的Context初始化。
4、Service Context
继续Service的启动流程(参考《Service启动流程分析》), ActivityThread中的scheduleCreateService(...)方法向mH发送了消息
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);
}通过handleCreateService(CreateServiceData data)方法创建Service:
private void handleCreateService(CreateServiceData data) {
...
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
}
...
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
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,
ActivityManager.getService());
service.onCreate();
...
}
...
}通用是通过ContextImpl的createAppContext(...)方法创建ContextImpl类型Context,并且将当前Service使用setOuterContext()方法让ContextImpl反向持有Service,最后调用Service的attach(...)方法
public final void attach(...) {
attachBaseContext(context);
mThread = thread; // NOTE: unused - remove?
mClassName = className;
mToken = token;
mApplication = application;
mActivityManager = (IActivityManager)activityManager;
mStartCompatibility = getApplicationInfo().targetSdkVersion
< Build.VERSION_CODES.ECLAIR;
}mBase是ContextImpl类型,持有了Service。Service又继承自ContextWrapper内部含有mBase,可以在Service调用所有Context中的方法。这样的设计让程序开发过程中几乎随处可以使用Context。
参考资料:
一篇文章让你彻底弄懂Context到底是什么,不懂还怎么做Android开发?
Android Application中的Context和Activity中的Context的区别


