曾经被问过一个问题:Android系统中的Context有几种?当时没怎么说清楚,现在再来聊聊这个问题。
Context是个抽象类,它有两个直接子类:ContextImpl和ContextWrapper。ContextImpl实现了Context中的所有抽象方法,ContextWrapper也实现了Context的抽象方法,但它的实现方式是通过调用其持有的ContextImpl实例mBase的对应的方法,所以它叫做Wrapper,可以理解成ContextImpl的包装类。
1 2 3 Context |--ContextImpl |--ContextWrapper
而Application、Service都是ContextWrapper的直接子类。此外,ContextWrapper还有其他直接子类,如ContextThemeWrapper、ReceiverRestrictedContext,而Activity则是ContextThemeWrapper的直接子类,因为它需要主题。ReceiverRestrictedContext则是给BroadcastReceiver使用的,后面说。
1 2 3 4 5 6 7 8 Context |--ContextImpl |--ContextWrapper |--Appliction |--Service |--ReceiverRestrictedContext |--ContextThemeWrapper |--Activity
这几个类的实例都是在ActivityThread中创建,其中的Context也是在这里面赋值的,分别来看一看
Activity 创建Activity时,最终会走到ActivityThread.performLauncherActivity方法里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private Activity performLaunchActivity (ActivityClientRecord r, Intent customIntent) { ContextImpl appContext = createBaseContextForActivity(r); Activity activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent); Application app = r.packageInfo.makeApplication(false , mInstrumentation); 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); if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } } private ContextImpl createBaseContextForActivity (ActivityClientRecord r) { ContextImpl appContext = ContextImpl.createActivityContext(this , r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig); return appContext; }
可以看到,创建一个Activity的过程主要有3步:一是通过反射创建Activity实例,二是准备相关的参数,其中包含ContextImpl实例和Application实例,接着是attach,在这个方法里初始化Activity的成员变量,其中有一个Application类型的变量mApplication,传入的Application是为了初始化这个变量。
Service 创建Service最终会走到ActivityThread.handleCreateService方法里
1 2 3 4 5 6 7 8 9 10 11 12 13 private void handleCreateService (CreateServiceData data) { ContextImpl context = ContextImpl.createAppContext(this , packageInfo); Application app = packageInfo.makeApplication(false , mInstrumentation); Service service = packageInfo.getAppFactory().instantiateService(cl, data.info.name, data.intent); service.attach(context, this , data.info.name, data.token, app, ActivityManager.getService()); service.onCreate(); }
和Activity类似,不再赘述。
BroadcastReceiver 创建BroadcastReceiver最终会走到ActivityThread.handleReceiver方法里
1 2 3 4 5 6 7 8 9 10 11 private void handleReceiver (ReceiverData data) { Application app = packageInfo.makeApplication(false , mInstrumentation); ContextImpl context = (ContextImpl) app.getBaseContext(); BroadcastReceiver receiver = packageInfo.getAppFactory().instantiateReceiver(cl, data.info.name, data.intent); receiver.onReceive(context.getReceiverRestrictedContext(), data.intent); }
可以看到,BroadcastReceiver没有直接使用创建的ContextImpl,而是通过context.getReceiverRestrictedContext()获取了ReceiverRestrictedContext,上面提过,它是ContextWrapper的直接子类,重写了其中的registerReceiver和bindService方法,方法里直接抛出异常,所以用BroadcastReceiver中的Context无法创建广播和服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class ReceiverRestrictedContext extends ContextWrapper { @Override public Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) { if (receiver == null ) { return super .registerReceiver(null , filter, broadcastPermission, scheduler); } else { throw new ReceiverCallNotAllowedException("BroadcastReceiver components are not allowed to register to receive intents" ); } } @Override public boolean bindService (Intent service, ServiceConnection conn, int flags) { throw new ReceiverCallNotAllowedException("BroadcastReceiver components are not allowed to bind to services" ); } }
Application 在创建上面3个的时候可以看到,Application都是通过packageInfo.makeApplication来创建的,packageInfo是个类型为LoadedApk类型的实例,具体看一看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public Application makeApplication (boolean forceDefaultAppClass, Instrumentation instrumentation) { if (mApplication != null ) { return mApplication; } ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this ); app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext); mApplication = app; instrumentation.callApplicationOnCreate(app); } 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; }
先创建了ContextImpl的实例,然后在Instrumentation中通过反射创建了Application实例,接着将上一步创建的ContextImpl实例通过attach方法传入,最后调用Application.onCreate方法
ContentProvider 四大组件说了三个,再说说最后一个ContentProvicer,虽然不是Context的子类,但也和Context相关。创建Provider在ActivityThread.installProvider方法中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private ContentProviderHolder installProvider (Context context, ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) { Context c = null ; ApplicationInfo ai = info.applicationInfo; if (context.getPackageName().equals(ai.packageName)) { c = context; } else if (mInitialApplication != null && mInitialApplication.getPackageName().equals(ai.packageName)) { c = mInitialApplication; } else { try { c = context.createPackageContext(ai.packageName, Context.CONTEXT_INCLUDE_CODE); } catch (PackageManager.NameNotFoundException e) { } ContentProvider localProvider = packageInfo.getAppFactory().instantiateProvider(cl, info.name); localProvider.attachInfo(c, info); }
视情况而定,ContextImpl的来源有多种,但最后都是通过attachInfo方法传入ContentProvider。
总结 回到最初的问题,Context有几种呢,就普遍性而言有3种:Application、Activity和Service,如果严谨一点,算上ReceiverRestrictedContext的话,那么就是4种。