Context及其子类源码分析(一)

看不明白UML的人,请移步不会用StarUML画类图的程序媛不是优秀的程序媛(一)

(一)Context类及其子类关系图如下图:

Context及其子类源码分析(一)_第1张图片

我们看源码会发现Context是个纯抽象类,ContextImpl和ContextWrapper两个类实现了Context的抽象方法。

Context提供了关于应用环境全局信息的接口。从Android系统角度来理解,Context是一个场景,代表与操作系统交互的一个过程,Context允许获取以应用为特征的资源和类型,是一个统领一些资源(应用程序环境变量等)的上下文。从代码角度来看,Context是一个纯抽象类。

ContextImpl是Context的具体实现类,源码位于android.app包中。但它只允许与它同包的类才能调用它。原本我写了如下代码,但是提示不存在ContextImpl这个类。


当然了,实际在Android中,Activity并不是这样简单一句话就创建的。在后面我们会有所分析。

ContextWrapper是Context类的实现,ContextWrapper中实现Context的方法全是通过mBase来实现的。这样ContextWrapper派生出的子类就可以在不改变原始Context(mBase)的情况下扩展Context的行为。即ContextWrapper构造函数中包含一个真正的Context引用,同时ContextWrapper中提供了attachBaseContext()用于给ContextWrapper对象中指定真正的Context对象,调用ContextWrapper的方法都会被转向其所包含的真正的Context对象。(多理解两遍这段话)

/**
 * Proxying implementation of Context that simply delegates all of its calls to
 * another Context.  Can be subclassed to modify behavior without changing
 * the original Context.
 */
public class ContextWrapper extends Context {
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }
    
    /**
     * Set the base context for this ContextWrapper.  All calls will then be
     * delegated to the base context.  Throws
     * IllegalStateException if a base context has already been set.
     * 
     * @param base The new base context for this wrapper.
     */
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

ContextThemeWrapper内部包含了与主题Theme相关的接口。这个类扩展的功能就是允许我们去修改或者替换包装的Context的主题。而Activity、Service和Application中,只有Activity需要用到Theme,所以Activity继承自ContextThemeWrapper,其他两个直接继承于ContextWrapper。

/**
 * A context wrapper that allows you to modify or replace the theme of the
 * wrapped context.
 */
public class ContextThemeWrapper extends ContextWrapper {
           ...
}

(二)Activity中ContextImpl实例化源码分析

以下分析内容全部来自于Android应用Context详解及源码解析。
因为原作者这部分内容实在写的太精彩了,无法删减任何一句话,因此在这表达对原作者的感谢!
Context的真正实现是ContextImpl,Activity、Service和Application的创建都是在ActivityThread中完成的。ActivityThread的handleLaunchActivity()方法会调用performLaunchActivity()方法去创建一个Activity实例。

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ......
            //已经创建好新的activity实例
            if (activity != null) {
                //创建一个Context对象
                Context appContext = createBaseContextForActivity(r, activity);
                ......
                //将上面创建的appContext传入到activity的attach方法
                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);
                //通过createBaseContextForActivity(r, activity);
                //创建appContext,然后通过activity.attach设置值。
                ...
            }
        ...
        return activity;
    }  
    private Context createBaseContextForActivity(ActivityClientRecord r,
            final Activity activity) {
        //实质就是new一个ContextImpl对象,调运ContextImpl的有参构造初始化一些参数    
        ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token);
        //特别特别留意这里!!!
        //ContextImpl中有一个Context的成员叫mOuterContext,通过这条语句就可将当前新Activity对象赋值到创建的ContextImpl的成员mOuterContext(也就是让ContextImpl内部持有Activity)。
        appContext.setOuterContext(activity);
        //创建返回值并且赋值
        Context baseContext = appContext;
        ......
        //返回ContextImpl对象
        return baseContext;
    }

再来看看activity.attach,也就是Activity中的attach方法,如下:

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) {
        //特别特别留意这里!!!
        //与上面createBaseContextForActivity方法中setOuterContext语句类似,不同的在于:
        //通过ContextThemeWrapper类的attachBaseContext方法,将createBaseContextForActivity中实例化的ContextImpl对象传入到ContextWrapper类的mBase变量,这样ContextWrapper(Context子类)类的成员mBase就被实例化为Context的实现类ContextImpl
        attachBaseContext(context);
        ......
    }

通过上面Activity的Context实例化分析再结合上面Context继承关系可以看出:

Activity通过ContextWrapper的成员mBase来引用了一个ContextImpl对象,这样,Activity组件以后就可以通过这个ContextImpl对象来执行一些具体的操作(启动Service等);同时ContextImpl类又通过自己的成员mOuterContext引用了与它关联的Activity,这样ContextImpl类也可以操作Activity。
下一篇:装饰者模式之Context应用(二)

你可能感兴趣的:(Context及其子类源码分析(一))