从源码角度看各种 Context

简介

做应用开发的对Context的熟悉度应该是仅次于Activity和Service的。Context,英文名上下文场景,代表着对当前运行场景下的各种信息的一种封装。例如,需要调用四大组件进行工作都要调用到Context,同时,通过Context也可以获取到Resource, Display, Theme, AssetManager, WallPaperManager这些资源对象。因为Context的使用方法实在太普及,实在可以说的上是安卓的第一课,这篇就不给实例了。

Context创建方法

想要知道都有哪几种不同的Context,从ContextImpl代码中寻找是最好的办法,以下列举了各种不同的Context创建接口及其调用场景:

接口 调用场景
createActivityContext startActivity时和新创建的Activity绑定
createAppContext startService和bindApplication时和新创建的service和application绑定
createApplicationContext 远程widget和notification时会用到
createConfigurationContext 用来获取或设置Resources, Theme等资源
createPackageContext installProvider时和新创建的ContentProvider绑定
createSystemContext system_server启动时被初始化,传入PackageManagerService中
createDisplayContext 不常用

四大组件与Application的Context

上面的表格已经概括出各种类别的Context, 但是我准备按照四大组件的角度去看看不同组件的Context是如何被初始化的以及区别是什么。

类图

Activity继承自ContextThemeWrapper; Service、Application继承自ContextWrapper。ContextWrapper的操作是聚合了Context的实例来实现的。真正的功能是在ContextImpl中进行实现。BroadcastReceiver与ContentProvider有些特殊,其实BroadcastReceiver是在调用onReceive方法时传入了Context对象,而ContentProvider聚合了Context对象并没有直接继承ContextWrapper。

Activity

Activity是最常用也是在四大组件中最复杂的一个

ActivityThread.java

  • private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  • ...
  • // 通过反射创建一个Activity实例
  • Activity activity = null;
  • try {
  • java.lang.ClassLoader cl = r.packageInfo.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);
  • }
  • } catch (Exception e) {
  • ...
  • }
  • try {
  • // 获取Aapplication实例
  • Application app = r.packageInfo.makeApplication(false, mInstrumentation);
  • if (activity != null) {
  • // 创建一个ContextImpl实例
  • Context appContext = createBaseContextForActivity(r, activity);
  • CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
  • Configuration config = new Configuration(mCompatConfiguration);
  • // 将Activity, Application, ContextImpl三者绑定
  • 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);
  • }
  • }
  • ...
  • private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
  • ...
  • ContextImpl appContext = ContextImpl.createActivityContext(
  • this, r.packageInfo, displayId, r.overrideConfig);
  • appContext.setOuterContext(activity);
  • Context baseContext = appContext;
  • ...
  • return baseContext;
  • }
  • }

ContextImpl.java

  • static ContextImpl createActivityContext(ActivityThread mainThread,
  • LoadedApk packageInfo, int displayId, Configuration overrideConfiguration) {
  • if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
  • return new ContextImpl(null, mainThread, packageInfo, null, null, false,
  • null, overrideConfiguration, displayId);
  • }

Application

ActivityThread.java

  • ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
  • try {
  • java.lang.ClassLoader cl = instrContext.getClassLoader();
  • mInstrumentation = (Instrumentation)
  • cl.loadClass(data.instrumentationName.getClassName()).newInstance();
  • } catch (Exception e) {
  • throw new RuntimeException(
  • "Unable to instantiate instrumentation "
  • + data.instrumentationName + ": " + e.toString(), e);
  • }
  • // 初始化instrumentation,绑定Context
  • mInstrumentation.init(this, instrContext, appContext,
  • new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
  • data.instrumentationUiAutomationConnection);
  • ...
  • Application app = data.info.makeApplication(data.restrictedBackupMode, null);
  • mInitialApplication = app;
  • ...
  • try {
  • mInstrumentation.onCreate(data.instrumentationArgs);
  • } catch (Exception e) {
  • throw new RuntimeException(
  • "Exception thrown in onCreate() of "
  • + data.instrumentationName + ": " + e.toString(), e);
  • }
  • try {
  • // 创建Application并调用onCreate方法
  • mInstrumentation.callApplicationOnCreate(app);
  • } catch (Exception e) {
  • if (!mInstrumentation.onException(app, e)) {
  • throw new RuntimeException(
  • "Unable to create application " + app.getClass().getName()
  • + ": " + e.toString(), e);
  • }
  • }

ContextImpl.java

  • static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
  • if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
  • return new ContextImpl(null, mainThread,
  • packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY);
  • }

Service

ActivityThread.java

  • private void handleCreateService(CreateServiceData data) {
  • ...
  • // 通过反射创建Service
  • LoadedApk packageInfo = getPackageInfoNoCheck(
  • data.info.applicationInfo, data.compatInfo);
  • Service service = null;
  • try {
  • java.lang.ClassLoader cl = packageInfo.getClassLoader();
  • service = (Service) cl.loadClass(data.info.name).newInstance();
  • } catch (Exception e) {
  • if (!mInstrumentation.onException(service, e)) {
  • throw new RuntimeException(
  • "Unable to instantiate service " + data.info.name
  • + ": " + e.toString(), e);
  • }
  • }
  • try {
  • if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
  • ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
  • context.setOuterContext(service);
  • // 得到Application实例,如果没有被实例化过则会创建一个
  • Application app = packageInfo.makeApplication(false, mInstrumentation);
  • // 将Context, Application与Service绑定
  • service.attach(context, this, data.info.name, data.token, app,
  • ActivityManagerNative.getDefault());
  • service.onCreate();
  • mServices.put(data.token, service);
  • try {
  • ActivityManagerNative.getDefault().serviceDoneExecuting(
  • data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
  • } catch (RemoteException e) {
  • // nothing to do.
  • }
  • } catch (Exception e) {
  • ...
  • }
  • }

BroadcastReceiver

  • static final class ReceiverDispatcher {
  • final BroadcastReceiver mReceiver;
  • ReceiverDispatcher(BroadcastReceiver receiver, Context context,
  • Handler activityThread, Instrumentation instrumentation,
  • boolean registered) {
  • ...
  • mReceiver = receiver;
  • ...
  • }
  • final class Args extends BroadcastReceiver.PendingResult implements Runnable {
  • ...
  • public void run() {
  • final BroadcastReceiver receiver = mReceiver;
  • ...
  • try {
  • // 通过反射调用BroadcastReceiver的onReceive并传入Context对象
  • ClassLoader cl = mReceiver.getClass().getClassLoader();
  • intent.setExtrasClassLoader(cl);
  • setExtrasClassLoader(cl);
  • receiver.setPendingResult(this);
  • receiver.onReceive(mContext, intent);
  • } catch (Exception e) {
  • ...
  • }
  • ...
  • }
  • }
  • }

ContextImpl.java

```java
private ContextImpl(ContextImpl container, ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
Display display, Configuration overrideConfiguration, int createDisplayWithId) {
mOuterContext = this;
...
}

public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
IIntentReceiver rd = null;
if (resultReceiver != null) {
if (mPackageInfo != null) {
...
} else {
...

  • // 初始化ReceiverDispatcher, 通过getOuterContext获取Context实例
  • rd = new LoadedApk.ReceiverDispatcher(resultReceiver, getOuterContext(),
top Created with Sketch.