前言
这篇文章来看关于context创建的源码流程。阅读文章需要对四大组件的启动流程有一定的了解,我在相关部分会简单介绍重要的知识点并给相关的文章链接。
在上一篇文章Context(装饰者模式)中讲解了context的相关实现类。经过前面的讨论,读者对于context在心中有了一定的理解。但始终觉得少点什么:activity是什么时候被创建的,他的contextImpl是如何被赋值的?Application呢?为什么说ContextProvider的context是Application,Broadcast的context是Activity?contextImpl又是如何被创建的?解决这些疑惑,就必须阅读源码了。阅读源码的好处非常多,上面我的讲述,都是基于我阅读源码之后的理解,而“一千个观众有一千个哈姆雷特”,阅读源码可以形成自己对整个机制自己的思考和理解,同时可以让自己对context那些知识真正落实到代码上,增强自己对知识的自信心。当别人和你意见不同的时候,你可以拍拍胸脯说:我看过源码,这个地方就是这样。是不是非常自信且傲娇?
然而阅读源码不是越多越好,而是把握整体的流程之后阅读关键源码,不要深入源码堆中无法自拔。例如我觉得activity的contextImpl是在Activity创建的过程中被赋值的,那么我就会去找activity的启动流程源码,然后只看和context有关的部分。提高效率的同时,还可以切中我们学习的点。下面的源码阅读我们给出整体流程,然后重点理解关键代码,其他的源码读者可自行下载源码去跟踪阅读一下。
“
这是context系列文章的第二部分,限于篇幅把context文章分为三部分:
第一部分:主要讲解什么是context以及关于context家族和相关实现类。Context(装饰者模式)
第二部分:主要讲不同Context的创建流程,包括Application、Activity、Service。
第三部分:也是最终篇,讲解剩下两个四大组件的context来源以及从更高的角度理解context。
读者可前往主页选择感兴趣的部分阅读,也可以完整阅读系统化学习context。
”
Application
Application应用级别的context,是在应用被创建的时候被创建的,是第一个被创建的context,也是最后一个被销毁的context。因而追踪Application的创建需要从应用程序的启动流程看起。应用启动的源码流程如下(简化版):

应用程序从ActivityThread的main方法开始执行,从Handler消息机制中我们知道main方法主要是开启线程的Looper以及handler,然后由AMS向主线程发送message控制应用的启动过程。因而我们可以把目标锁定在图中的最后一个方法:handleBindApplication
,Application最有可能在这里被创建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
private void handleBindApplication(AppBindData data) { ... // 创建LoadedApk对象 data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo); ... Application app; ... try { // 创建Application app = data.info.makeApplication(data.restrictedBackupMode, null); ... } try { ... // 回调Application的onCreate方法 mInstrumentation.callApplicationOnCreate(app); } ... }
|
handleBindApplication
的参数AppBindData是AMS给应用程序的启动信息,其中就包含了“权限凭证”——ApplicationInfo等。LoadedApk就是通过这些对象来创建获取对系统资源的访问权限,然后通过LoadApk来创建ContextImpl以及Application。
这里我们只关注和context创建有关的逻辑,前面启动程序的源码以及AMS如何处理,这里就不讲了,读者有兴趣可以读ContextProvider启动流程这篇文章,其中对ContextProvider的启动过程就有对上述源码进行追踪详解。
那么接下来我们继续关注Application是如何创建的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) { // 如果application已经存在则直接返回 if (mApplication != null) { return mApplication; } ... Application app = null; String appClass = mApplicationInfo.className; ... try { java.lang.ClassLoader cl = getClassLoader(); ... // 创建ContextImpl ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); // 利用类加载器加载我们在AndroidMenifest指定的Application类 app = mActivityThread.mInstrumentation.newApplication( cl, appClass, appContext); // 把Application的引用给comtextImpl,这样contextImpl也可以很方便地访问Application appContext.setOuterContext(app); } ... mActivityThread.mAllApplications.add(app); // 把app设置为mApplication,当我们调用context.getApplicationContext就是获取这个对象 mApplication = app;
if (instrumentation != null) { try { // 回调Application的onCreate方法 instrumentation.callApplicationOnCreate(app); } ... } ... return app; }
|
代码的逻辑也不复杂,首先判断LoadedApk对象中的mApplication是否存在,否则创建ContextImpl,再利用类加载器和contextImpl创建Application,最后把Application对象赋值给LoadedApk的mApplication,再回调Application的onCreate方法。我们先来看一下contextImpl是如何创建的:
1 2 3 4 5 6 7 8 9 10
| 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; }
|
这里直接new了一个ContextImpl,同时给ContextImpl赋值访问系统资源相关的“权限”对象——ActivityThread,LoadedApk等。让我们再回到Application的创建过程。我们可以猜测,在newApplication
包含的逻辑肯定有:利用反射创建Application,再把contextImpl赋值给Application。原因是每个人自定义的Application类不同,需要利用反射来创建对象,其次Application中的mBase属性是对ContextImpl的引用。看源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 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.class(api29) final void attach(Context context) { attachBaseContext(context); mLoadedApk = ContextImpl.getImpl(context).mPackageInfo; } ContextWrapper.class(api29) Context mBase; protected void attachBaseContext(Context base) { if (mBase != null) { throw new IllegalStateException("Base context already set"); } mBase = base; }
|
结果非常符合我们的猜测,先创建Application对象,再把ContextImpl通过Application的attach方法赋值给Application。然后Application的attach方法调用了ContextWrapper的attachBaseContext方法,因为Application也是继承自ContextWrapper。这样,就把ContextImpl赋值给Application的mBase属性了。
再回到前面的逻辑,创建了Application之后需要回调onCreate方法:
1 2 3 4 5
| public void callApplicationOnCreate(Application app) { app.onCreate(); }
|
简单粗暴,直接回调。到这里,Application的创建以及context的创建流程就走完了。但是需要注意的是,全局初始化需要在onCreate中进行,而不要在Application的构造器中执行。从代码中我们可以看到ContextImpl是在Application被创建之后再赋值的。
Activity
Activity的context也是在Activity创建的过程中被创建的,这个就涉及到Activity的启动流程,这里涉及到三个流程:应用程序请求AMS,AMS处理请求,应用程序响应Activity创建事务:

依然,我们专注于Activity的创建流程,其他的读者可阅读Activity启动流程这篇文章了解。和Application一样,Activity的创建时由AMS来控制的,AMS向应用程序进程发送消息来执行具体的启动逻辑。最后会执行到handleLaunchActivity
这个方法:
1 2 3 4 5 6 7 8 9
| public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) { ... final Activity a = performLaunchActivity(r, customIntent); ... return a; }
|
最终的就是中间这句代码,进入看源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ... // 创建Activity的ContextImpl ContextImpl appContext = createBaseContextForActivity(r); Activity activity = null; try { // 利用类加载创建activity实例 java.lang.ClassLoader cl = appContext.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); ... } try { // 创建Application Application app = r.packageInfo.makeApplication(false, mInstrumentation); ... if (activity != null) { ... // 把activity设置给context,这样context也可以访问到activity了 appContext.setOuterContext(activity); // 调用activity的attach方法把contextImpl设置给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);
int <span class="hljs-attr">theme</span> = r.activityInfo.getThemeResource()<span class="hljs-comment">;</span> if (theme != 0) { // 设置主题 activity.setTheme(theme)<span class="hljs-comment">;</span> } ... // 回调onCreate方法 if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } ... } ... } ... return activity; }
|
代码的逻辑不是很复杂,首先创建Activity的ContextImpl,利用类加载创建activity实例,然后再通过LoadedApk创建Application,这个方法在前面我们讲过,如果Application已经创建会直接返回已经创建的对象。然后把activity设置给context,这样context也可以访问到activity了。这里要注意,前面讲到使用Activity的context会造成内存泄露,那么可不可以用Activity的contextImpl对象呢?答案是不可以,因为ContextImpl也会持有Activity的引用,需要特别注意一下。随后再调用activity的attach方法把contextImpl设置给activity。后面是设置主题和回调onCreate方法,我们就不深入了,主要看看attach方法:
1 2 3 4 5 6
| final void attach(Context context,...) { attachBaseContext(context); ... }
|
这里省略了大量的代码,只保留关键一句:attachBaseContext
,是不是很熟悉?调用ContextWrapper的方法来给mBase属性赋值,和前面Application是一样的,就不再赘述。
Service
依然只关注关键代码流程,先看Service的启动流程图:

Service的创建过程也是受AMS的控制,同样我们看到创建Service的那一步,最终会调用到handleCreateService
这个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| private void handleCreateService(CreateServiceData data) { ... LoadedApk packageInfo = getPackageInfoNoCheck( data.info.applicationInfo, data.compatInfo); Service service = null; try { java.lang.ClassLoader cl = packageInfo.getClassLoader(); service = packageInfo.getAppFactory() .instantiateService(cl, data.info.name, data.intent); } ... try { ... ContextImpl context = ContextImpl.createAppContext(this, packageInfo); context.setOuterContext(service);
Application <span class="hljs-attr">app</span> = packageInfo.makeApplication(<span class="hljs-literal">false</span>, mInstrumentation)<span class="hljs-comment">;</span> service.attach(context, this, data.info.name, data.token, app, ActivityManager.getService())<span class="hljs-comment">;</span> service.onCreate()<span class="hljs-comment">;</span> mServices.put(data.token, service)<span class="hljs-comment">;</span> ... } ...}
|
Service的逻辑就相对简单了,同样创建service实例,再创建contextImpl,最后把contextImpl通过Service的attach方法赋值给mBase属性,最后回调Service的onCreate方法。过程和上面的很像,这里就不再深入讲了,感兴趣的读者可自行去阅读源码,也可以阅读Android中Service的启动与绑定过程详解(基于api29)这篇文章了解Service的详细内容。
最后
文章讲解了三大context实现类的启动流程,相信通过源码阅读对context有一个更加彻底的理解。四大组件还有广播以及内容提供器,限于篇幅就放在下一部分讲了。
上一篇:Context装饰者模式
下一篇:ApplicationThread