关于Context和ContextImpl还有ContextWrapper的关系

关于Context和ContextImpl还有ContextWrapper的关系

1.Context和ContextImpl还有ContextWrapper的关系

img

​ 图一.Context和ContextImpl还有ContextWrapper的关系示意图

1.1.ContextImpl是Context的实现类

从Context和ContextImpl的源代码中,可以看出Context是一个抽象类,具体的实现类是ContextImpl

public abstract class Context {

Context.java文件

class ContextImpl extends Context {....}

ContextImpl.java文件

1.2.ContextWrapper是Context的包装类

从ContextWrapper的源代码可以看出,ContextWrapper继承自Context; 并且ContextWrapper类持有Context的引用;

所以最终是要通过java的多态这个属性,调用Context类的相关方法,实际上是调用ContextImpl类里面的方法

public class ContextWrapper extends Context {
    @UnsupportedAppUsage
    Context mBase;

ContextWrapper.java文件

2.ContextImpl跟ContextWrapper的关联过程

2.1.ContextWrapper可以关联的可能入口

根据下面的ContextWrapper的源码的解读,如果ContextWrapper关联ContextImpl,

只有两个地方可以把Context作为参数传进来

第一个:ContextWrapper的构造函数

第二个:attachBaseContext函数

这两个函数都会把context 赋值给名字为mBase的Context的属性

public class ContextWrapper extends Context {
    @UnsupportedAppUsage
    Context mBase;

    @GuardedBy("mLock")
    @VisibleForTesting
    public List<ComponentCallbacks> mCallbacksRegisteredToSuper;

    private final Object mLock = new Object();

    public ContextWrapper(Context base) {
        mBase = base;
    }

    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

2.2.Context创建过程

public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        
             //TODO 
             ......
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            // The network security config needs to be aware of multiple
            // applications in the same process to handle discrepancies
            NetworkSecurityConfigProvider.handleNewApplication(appContext);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
            if (!mActivityThread.mInstrumentation.onException(app, e)) {
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                throw new RuntimeException(
                    "Unable to instantiate application " + appClass
                    + " package " + mPackageName + ": " + e.toString(), e);
            }
        }
        //TODO 
        ......

        return app;
    }

LoadedApk.java

在LoadedApk的函数makeApplication中,下面这段语句通过调用了ContextImpl.createAppContext 生成了ContextImpl对象

ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);

在ContextImpl类中,createAppContext函数,调用了另外一个带3个参数的重写函数createAppContext,

可以看出在这个函数里面,通过ContextImpl context = new ContextImpl 这个语句 创建了ContextImpl类的对象,

然后通过函数返回,返回了这个ContextImpl类的对象.

@UnsupportedAppUsage
    static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
        return createAppContext(mainThread, packageInfo, null);
    }

    static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo,
            String opPackageName) {
        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
        ContextImpl context = new ContextImpl(null, mainThread, packageInfo,
            ContextParams.EMPTY, null, null, null, null, null, 0, null, opPackageName);
        context.setResources(packageInfo.getResources());
        context.mContextType = isSystemOrSystemUI(context) ? CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI
                : CONTEXT_TYPE_NON_UI;
        return context;
    }

上面的步骤创建了appContext,然后通过下面的函数调用把对象appContext传递下去

app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);

在Instrumentation源代码中,newApplication 函数中,Application的attach函数,通过此函数, 把context传递下去

    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;
    }

Instrumentation.java

Application类的attach函数,在这个函数中,会把传递进来的context 传递给attachBaseContext函数, attachBaseContext 函数是父类ContextWrapper的函数

同时验证了上面的结论(2.1.ContextWrapper可以关联的可能入口)

public class Application extends ContextWrapper implements ComponentCallbacks2 {
    @UnsupportedAppUsage
    /* package */ final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }

Application.java

在ContextWrapper的源代码中,可以看到context会在attachBaseContext中赋值给名字为mBase的Context对象的属性

public class ContextWrapper extends Context {
    @UnsupportedAppUsage
    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;
    }

ContextWrapper.java

到此处为止,ContextImpl 跟ContextWrapper 的关联已经完成

引用:
Android 开发者,你真的懂Context吗?

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦想全栈程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值