Context真正的实现与Context设计模式

说明:基于API 26的源码分析java

1. 类图

context_01

Context: 是一个抽象类。bash

ContextImpl: 是Context真正的实现类。app

ContextWrapper: 继承Context,是一个包装类,有一个mBase的成员变量,mBase是Context类型,Context抽象方法都是由mBase实现的。子类经过调用attachBaseContext方法替换mBase成员变量。源码分析

Application, Activity, Service都是继承ContextWrapper,它们的真正的实现都是ContextImpl实例,ui

经过attachBaseContext方法把ContextImpl实例赋值给mBase。this

因此在activity或者application中经常使用的方法,例如 :spa

  • getSharedPreferences(String name, int mode)
  • startActivity
  • sendBroadcast
  • 等等等

上述的经常使用的方法真正实现都是在ContextImplcode

2. 源码分析

2.1 Application建立为例

Application的实例从ActivityThread的handleBindApplication(),再到LoadedApk的makeApplication()建立的。orm

第一步:LoadedApk的makeApplication方法

context_02

cl是ClassLoader, appClass是Application的全类名, 经过ContextImpl.createAppContext建立一个ContextImpl实例,把ContextImpl实例、cl、appClass传到mInstrumentation.newApplication方法建立Application实例。cdn

第二步: Instrumentation的newApplication方法

public Application newApplication(ClassLoader cl, String className, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return newApplication(cl.loadClass(className), context);
    }

static public Application newApplication(Class<?> clazz, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        app.attach(context);
        return app;
    }

//Application的attach方法:
/* package */ final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }
复制代码

先经过classLoader的loadClass(className)获取application的class,再经过clazz.newInstance()建立Application实例,接着调用app.attach(context)方法完成初始化。 Application的attach方法里是经过attachBaseContext(context), 把第一步建立的ContextImpl实例赋值给ContextWrapper的mBase成员变量。 到此Application实例建立就完成啦。

2.2 Activity建立为例

Activity建立和Application的建立相似,在ActivityThread的performLaunchActivity方法里

第一步:ActivityThread的performLaunchActivity方法

context_03

context_04

经过creatBaseContextForActivity方法建立ContextImpl实例,接着经过mInstrumentation.newActivity建立Activity实例,Activity实例经过classloader,加载className,调用clazz的newInstance方法建立。再接着调用activity.attach方法完成初始化。

第二步:Activity的attach方法

context_05

Activity的attach方法里是经过attachBaseContext(context), 把第一步建立的ContextImpl实例赋值给ContextWrapper的mBase成员变量。 到此Activity实例建立就完成啦。

2.3 Service建立为例

Service里的Context建立和Activity差很少

第一步:定位到ActivityThread的handleCreateService方法

java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
service.onCreate();
复制代码

调用ContextImpl的createAppContext()建立ContextImpl,调用setOuterContext()把service存储在ContextImpl的mOuterContext成员变量中,调用service.attach(),再调用service.onCreate()

第二步: Service的attach方法

public final void attach(
        Context context,
        ActivityThread thread, String className, IBinder token,
        Application application, Object activityManager) {
    attachBaseContext(context);
    mThread = thread;
    mClassName = className;
    mToken = token;
    mApplication = application;
    mActivityManager = (IActivityManager)activityManager;
    mStartCompatibility = getApplicationInfo().targetSdkVersion
            < Build.VERSION_CODES.ECLAIR;
}
复制代码

经过attachBaseContext(context), 把第一步建立的ContextImpl实例赋值给ContextWrapper的mBase成员变量。

3. 总结

ContextWrapper继承Context。Application, Activity, Service都是继承ContextWrapper,它们的真正的实现都是ContextImpl实例,经过attachBaseContext方法把ContextImpl实例赋值给mBase。Context里抽象方法真正实现都是在ContextImpl里。

还有一个共同点:

  • Application 或者Activity建立后都会调用 contextImpl.setOutContext(context),把Application 或者Activity实例存储在ContextImpl的mOuterContext成员变量中
相关文章
相关标签/搜索