征服安卓面试官路漫漫:从源码深扒一下四大组件和Context( 二 )


所以 , 装饰器模式通过组合和扩展装饰类 , 来给不同的具体对象提供了不同的功能扩展 。
Activity、Service、Application 最终都是继承自装饰类 ContextWrapper, ContextWrapper 通过 attachBaseContext() 方法来获取实际做事的 ContextImpl 对象 。 所以这些组件的创建过程中 , 一定会在某一时机调用 attachBaseContext() 方法对 mBase 对象进行赋值 , 让我们从源码里面找找答案 。
四大组件和 ContextActivity 和 Context先说 Activity , Activity 的启动过程极其复杂 , 我们就直接从 ActivityThread 的 performLaunchActivity() 方法看起 。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {ActivityInfo aInfo = r.activityInfo;if (r.packageInfo == null) {// 1. 获取 LoadedApk 对象r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,Context.CONTEXT_INCLUDE_CODE);}......// 2. 创建 ContextImpl 对象ContextImpl appContext = createBaseContextForActivity(r);Activity activity = null;try {java.lang.ClassLoader cl = appContext.getClassLoader();// 3. 反射创建 Activity 对象activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);......} catch (Exception e) {......}try {// 4. 创建 Application 对象Application app = r.packageInfo.makeApplication(false, mInstrumentation);if (activity != null) {......appContext.setOuterContext(activity);// 5. 绑定 activityactivity.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);......int theme = r.activityInfo.getThemeResource();if (theme != 0) {// 设置主题activity.setTheme(theme);}// 6. 回调 onCreate()if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}......r.activity = activity;}r.setState(ON_CREATE);mActivities.put(r.token, r);} catch (SuperNotCalledException e) {throw e;} catch (Exception e) {......}return activity;}整理一下大致的执行流程:

  1. 获取 LoadedApk 对象 , 表示加载过的 Apk, 通常一个 App 对应着一个 LoadedApk
  2. 通过 createBaseContextForActivity() 方法创建 ContextImpl 对象
  3. 反射创建 Activity 对象
  4. 创建 Application 对象 , 这里也是用的反射 。 如果开发者没有声明自己的 Application 的话 , 就是默认的 androoid.app.Application
  5. 调用 activity.attach(), 这个方法很重要 , 后面详细说
  6. 回调 onCreate()
接着就是 Activity 正常的生命周期流程了 。
重点看一下 createBaseContextForActivity() 方法和 attach() 方法 。
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);......return appContext;}调用了 ContextImpl.createActivityContext() 方法 。
static ContextImpl createActivityContext(ActivityThread mainThread,LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,Configuration overrideConfiguration) {......// 创建 ContextImpl 对象ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,activityToken, null, 0, classLoader);......final ResourcesManager resourcesManager = ResourcesManager.getInstance();context.setResources(resourcesManager.createBaseActivityResources(activityToken,packageInfo.getResDir(),splitDirs,packageInfo.getOverlayDirs(),packageInfo.getApplicationInfo().sharedLibraryFiles,displayId,overrideConfiguration,compatInfo,classLoader));context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,context.getResources());return context;}装饰类 ContextWrapper 真正需要的 ContextImpl 对象现在已经创建出来了 , 但是还没有绑定到 Activity。 继续看 Activity.attach() 方法 , 注意attach() 方法的第一个参数就是刚刚创建出来的 ContextImpl 对象 。
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()attachBaseContext(context);......// 创建 PhoneWindowmWindow = new PhoneWindow(this, window, activityConfigCallback);......mWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE),mToken, mComponent.flattenToString(),(info.flags......}你对 attachBaseContext() 方法应该还有印象 。 ContextWrapper 正是通过这个方法给 mBase 对象赋值 , 拿到真正的 ContextImpl 对象 。 到这里 , 整个逻辑就通顺了 。