征服安卓面试官路漫漫:从源码深扒一下四大组件和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;}
整理一下大致的执行流程:
- 获取 LoadedApk 对象 , 表示加载过的 Apk, 通常一个 App 对应着一个 LoadedApk
- 通过 createBaseContextForActivity() 方法创建 ContextImpl 对象
- 反射创建 Activity 对象
- 创建 Application 对象 , 这里也是用的反射 。 如果开发者没有声明自己的 Application 的话 , 就是默认的 androoid.app.Application
- 调用 activity.attach(), 这个方法很重要 , 后面详细说
- 回调 onCreate()
重点看一下 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 对象 。 到这里 , 整个逻辑就通顺了 。
- 王文鉴|从工人到千亿掌门人,征服华为三星,只因他36年只坚持做一件事
- 手机|预算只有五千,买4G的iPhone11还是买国产5G安卓机?
- 华为|安兔兔10月安卓性能榜:华为Mate40 Pro第一 麒麟9000碾压骁龙865
- 重磅!高通骁龙888正式发布,安卓手机将大变
- 三年Java开发,刚从美团、京东、阿里面试归来,分享个人面经
- 华为|从工人到千亿掌门人,征服华为三星,只因他36年只坚持做一件事
- java面试题整理
- 面试官:问你一个,Spring事务是如何传播的?
- 安卓手机用户必看:谷歌公布2020年度最佳应用和游戏
- 程序员面试主要看哪些 该怎么准备面试内容