Context使用场景总的来说分为两大类:
- 使用Context调用方法,比如启动Activity、访问资源、调用系统级服务等。
- 调用方法时传入Context,比如弹出Toast、创建Dialog等。
Activity、Service和Application都间接的继承自Context,一个应用进程中有多少个Context,这个数量等于Activity和Service的总个数加1,1指的是Application。
Context是一个抽象类,它的内部定义了很多方法及静态常量,具体实现类为ContextImpl。和Context相关联的类除了ContextImpl还有ContextWrapper,ContextThemeWrapper和Activity等。
ContextImpl和ContextWrapper继承自Context,ContextWrapper内部包含Context类型的mBase对象,mBase具体指向ContextImpl。ContextImpl提供了很大功能,但是外界需要使用并拓展ContextImpl的功能,因此设计上使用了装饰模式,ContextWrapper是装饰类,它对ContextImpl进行包装,ContextWrapper主要是起了方法传递的作用,ContextWrapper中几乎所有的方法都是调用ContextImpl的相应方法来实现的。
ContextThemeWrapper、Service、Application都继承自ContextWrapper,它们都可以通过mBase来使用Context的方法,同时它们也是装饰类,在ContextWrapper的基础上又添加了不同的功能。
ContextThemeWrapper中包含和主题相关的方法,Activity继承于它。
Context的关联类采用了装饰模式,主要优点:
- 使用者(比如Service)能够更方便地使用Context
- 如果ContextImpl发生了变化,它的装饰类ContextWrapper不需要做任何修改
- ContextImpl的实现不会暴露给使用者,使用者也不必关心ContextImpl的实现
- 通过组合而非继承的方式拓展ContextImpl的功能,在运行时选择不同的装饰类,实现不同的功能
Application Context的创建过程
ActivityThread类作为应用程序进程的主线程管理类,它会调用内部类ApplicaitonThread的scheduleLaunchActivity方法来启动Activiy,在ApplicationThread的scheduleLaunchActivity方法中向H类发送LAUNCH_ACTIVITY类型的消息,在H类的handleMessage方法中对此消息进行处理,通过getPackageInfoNoCheck方法获得LoadedApk类型的对象,并将其赋值给ActivityClientRecord的成员变量packageInfo,然后调用ActivityThread的handleLaunchActivity方法,此方法又调用了performLaunchActivity方法,在此方法中有很多重要逻辑,这里只分析和Application Context相关的逻辑。
在performLaunchActivity方法中,会调用r.packageInfo.makeApplication方法,packaeInfo时LoadedApk类型的,在LoadedApk的makeApplication方法中,先判断如果mApplication不为null则直接返回mApplication,如果为null,则通过ContextImpl的createContext方法来创建ContextImpl;在Instrumentation的newApplication方法中传入了ClassLoader类型的对象以及创建的ContextImpl对象,创建了Application,将Application赋值给ContextImpl的成员变量mOuterContext,这样ContextImpl中也包含了Application的引用。将Application赋值给LoadedApk的成员变量mApplication,这里mApplication是Application类型的,用来代表ApplicationContext。Instrumentation的newApplication方法中,通过反射来创建Application,并调用其attach方法,将ContextImpl传进去。在attach方法中调用了attachBaseContext方法,它在Application父类ContextWrapper中实现,将传过来的ContextImpl类型的base赋值给ContextWrapper的成员变量mBase,这样ContextWrapper中就可以使用Context的方法,而Application继承自ContextWrapper,同样可以使用Context的方法。Application的attach方法的作用就是使Application可以使用Context方法,这样Application才可以用来代表ApplicationContext。
Application Context的获取过程
通过getApplicationContext方法来获取Application Context,此方法在ContextWrapper中实现,会调用ContextImpl中的getApplicationContext方法,在此方法中,如果LoadedApk类型的mPackageInfo不为null,则调用LoadedApk的getApplication方法,否则调用ActivityThread的getApplication方法,由于应用程序已启动,LoadedApk不会为null,因此会调用LoadedApk的getApplication方法,返回mApplication对象。
Activity的Context创建过程
ActivityThread是应用程序进程的主线程管理类,它的内部类ApplicationThread会调用scheduleLaunchActivity方法来启动Activity,此方法将启动Activity的参数封装成ActivityClientRecord,sendMessage方法将向H类发送LAUNCH_ACTIVITY的消息,并将ActivityClientRecord传递过去。H类的handleMessage方法会对LAUNCH_ACTIVITY消息进行处理,其中调用了ActivityThread的handleLaunchActivity方法,而此方法又调用了performLaunchActivity方法。在performLaunchActivity中,通过createBaseContextForActivity方法来创建Activity的ContextImpl,通过Instrumentation的newActivity方法创建Activity实例,然后调用ContextImpl的setOuterContext方法,将Activity实例赋值给ContextImpl的成员变量mOuterContext,然后将ContextImpl实例传入Activity的attach方法中,这样ContextImpl也可以调用Activity的变量和方法。最后调用mInstrumentation的callActivityOnCreate方法调用Activity的onCreate方法。在createBaseContextForActivity方法中会调用ContextImpl的createActivityContext方法来创建ContextImpl。
再看Activity的attach方法,此方法中会创建PhoneWindow,代表应用程序窗口,PhoneWindow在运行中间会接触很多事件,比如点击菜单弹出,屏幕焦点变化等事件,这些事件需要转发给关联的Activity,转发操作通过Window.Callback接口实现,Activity实现了这个接口,将当前Activity通过Window的setCallback方法传递给PhoneWindow,为PhoneWindow设置WindwoManager,并将WindowManager赋值给Activity的成员变量mWindowManager,这样Activity就可以通过getWindowManager方法来获取WindowManager。
开始的attachBaseContext方法在ContextThemeWrapper中实现,直接调用了父类ContextWrapper的attachBaseContext方法,将一路传递过来的ContextImpl类型的base赋值给ContextWrapper的成员变量mBase,这样ContextWrapper的功能就可以交由ContextImpl来处理。
在Activity的启动过程中创建ContextImpl,并赋值给ContextWrapper的成员变量mBase,Activity继承自ContextWrapper的子类ContextThemeWrapper,这样在Activity中就可以使用Context中定义的方法了。
Service的Context创建过程
Service的Context创建过程与Activity的Context创建过程类似,是在Service的启动过程中被创建的。ActivityThread的内部类ApplicationThread会调用scheduleCreateService方法来启动Service,sendMessage方法向H类发送CREATE_SERVICE消息,H类的handleMessage方法会处理此消息,调用了ActivityThread的handleCreateService方法,通过ContextImpl的createApplicationContext方法创建了ContextImpl,并将其传入Service的attach方法中,attach方法中会调用ContextWrapper的attachBaseContext方法,将传递过来的ContextImpl类型的base赋值给ContextWrapper的成员变量mBase,这样ContextWrapper中就可以使用Context的方法,而Service继承自ContextWrapper同样可以使用Context的方法。