Context也就是上下文对象,是Android常用的类。Android的四大组件都会涉及Context。
Context的关联类:
Context是一个应用程序环境信息的接口。它的使用场景主要可以分为两类:
- 使用Context调用方法,比如:启动Activity,访问资源,调用系统级服务等。
- 调用方法时传入Context,比如:弹出Toast,创建Dialog等。
Activity,Service和Application都是间接的继承自Context,因此在一个应用程序进程中有多少个Context,这个数量等于Activity,Service,Application的总个数。Context是一个抽象类,它的内部定义了很多方法以及静态常量,它的具体实现类有ContextWrapper,ContextImpl,和Context相关联的类,除了它们以外,还有Activity,ContextThemeWrapper等等。
ContextImpl和ContextWrapper都继承自Context,在ContextWrapper中包含了很多的Context类型的mBase对象,mBase对象具体指的是ContextImpl,ContextImpl提供了很多的功能,但是外界需要使用并且扩展ContextImpl的功能,因此使用了装饰模式。而ContextWrapper是装饰类,它对ContextImpl进行包装。其中ContextWrapper它几乎所有的方法都是调用ContextImpl对应的方法来实现的。因为ContextThemeWrapper,Service,Application都是继承自ContextWrapper类,这样它们都可以通过mBase来使用Context的方法,同时它们也是装饰类,在ContextWrapper的基础上又添加了不同的功能。例如:在ContextThemeWrapper中包含与主题相关的方法,因此需要主题的Activity继承ContextThemeWrapper,而不需要主题的Service继承了ContextWrapper。
Application Context的创建过程:
我们可以通过调用getApplicationContext方法来获取应用程序全局的Application Context。那么这个Application Context是怎么创建的呢?在一个应用程序启动之后,应用程序就会有一个全局的Application Context,那么我们从应用程序启动过程开始入手。
ActivityThread类作为应用程序进程的主线程管理类,它会调用它的内部类ApplicationThread类scheduleLaunchActivity方法来启动Activity,具体参考:四大组件的启动过程的3.ActivityThread启动Activity的过程。我们直接快进到performLaunchActivity方法中的通过r.packageInfo. makeApplication方法内部调用Application的onCreate方法来创建Application。其中:r.packageInfo是ActivityClientRecord的成员变量packageInfo,它是LoadedApk类型的。
继续来看makeApplication方法:首先判断mApplication是否为空,不为空则直接返回。但是在第一次启动应用程序时,它是为空的。那么就再后续调用ContextImpl的createAppContext方法来创建ContextImpl。然后在调用mActivityThread.mInstrumentation.newApplication方法,并且传入ClassLoader类型的对象以及创建的ContextImpl对象来创建Application对象。接着把Application赋值给ContextImpl的Context类型的成员变量mOuterContext,这样就完成了ContextImpl中包含对Application的引用。然后把Application赋值给LoadedApk的成员变量mApplication,它是Application类型的对象,它用来代表Application Context。
分析:mActivityThread.mInstrumentation.newApplication方法是怎么创建Application的,Instrumentation中有两个newApplication的重载方法。最终调用的newApplication方法它通过ClassLoader的newInstance方法(反射)来创建Application,并且调用了Application的attach方法,传入ContextImpl对象。
Application的attach方法中调用了attachBaseContext方法,它在ContextWrapper中实现。它会把传入的ContextImpl赋值给ContextWrapper的成员变量mBase,这样在ContextWrapper中就可以使用Context的方法,而Application也可以使用。所以Application的attach方法就是使Application可以使用Context的方法,这样Application才可以代表Application Context。
Application Context的获取过程:
我们知道getApplicationContext方法来获取应用程序全局的Application Context。getApplicationContext方法在ContextWrapper类中实现。它返回了mBase的getApplicationContext方法,其中mBse是ContextImpl类型的,它的getApplicationContext方法在判断LoadedApk不为空后,就调用LoadedApk的getApplication方法,否则调用ActivityThread的getApplication方法。而在应用程序已经启动的情况下,不为空。所以LoadedApk的getApplication方法它返回了一个mApplication变量,也就是在makeApplication方法中被赋值给LoadedApk的那个成员变量mApplication。
Activity的Context的创建过程:
我们还是从Activity的启动开始:scheduleLaunchActivity方法快进到performLaunchActivity方法。具体参考:四大组件的启动过程的3.ActivityThread启动Activity的过程。在performLaunchActivity方法中调用createBaseContextForActivity方法创建启动Activity的上下文环境ContextImpl。并且传入Activity的attach方法初始化Activity。还有通过ContextImpl的setOuterContext方法,用于将之前创建的Activity实例赋值给ContextImpl的成员变量mOuterContext,这样使得ContextImpl也可以访问Activity的变量和方法。
我们来看createBaseContextForActivity方法:它会调用ContextImpl的createActivityContext方法来创建ContextImpl。
继续来看Activity的attach方法:它创建了PhoneWindow,代表应用程序窗口,而在PhoneWindow触发的事件通过Window.Callbock接口实现转发给关联的Activity。然后Window的setCallback方法将当前Activity传递给PhoneWindow。之后为PhoneWindow设置WindowManager。接着通过getWindowManager方法获取并且赋值给Activity的成员变量mWindowManager。而attachBaseContext方法在ContextThemeWrapper中实现。
attachBaseContext方法它调用了父类ContextWrapper的attachBaseContext方法将一路传递过来的Activity的ContextImpl赋值给ContextWrapper的成员变量mBase。这样ContextWrapper的功能也可以交给ContextImpl来处理。
Service的Context的创建过程:
我们从Service的启动过程开始:从scheduleCreateService方法快进到handleCreateService方法。具体参考:四大组件的启动过程的2.ActivityThread启动Service。该方法通过通过ContextImpl的createAppContext方法创建上下文环境,并且把该ContextImpl传入Service的attach方法。
Service的attach方法主要看它调用了ContextWrapper的attachBaseContext方法,将一路传递过来的ContextImpl赋值给ContextWrapper的成员变量mBase。