美文网首页
和Context类关联的组件

和Context类关联的组件

作者: gczxbb | 来源:发表于2019-01-27 13:19 被阅读18次

组件Context

组件Activity、Service以及Application都和Context有关联。在android api23的源码中,他们的关系图。 组件与Context的关系.jpg

他们都继承ContextWrapper,Activity中间还有一层和关于主题的的装饰者。在ContextWrapper类中,attachBaseContext方法,加载具体的被装饰对象,即ContextImpl。

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

Activity、Service和Application的内部Context,都是通过上面方法初始化的。在Activity的attach方法时,调用该方法。实体通过ContextImpl的静态方法创建。

static ContextImpl createActivityContext(ActivityThread mainThread,
            LoadedApk packageInfo, int displayId, Configuration overrideConfiguration) {
    if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
    return new ContextImpl(null, mainThread, packageInfo, null, null, false,
                null, overrideConfiguration, displayId);
}

该方法创建Activity内部的ContextImpl。Service和Activity一样,也是在attach方法调用attachBaseContext方法,创建ContextImpl的静态方法不同。

static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
    if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
    return new ContextImpl(null, mainThread,
                packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY);
}

Application和Service的ContextImpl创建方法是一样的,也是调用createAppContext方法创建。Application的attach方法,attachBaseContext设置内部Context。

ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
appContext.setOuterContext(app);

ContextImpl的setOuterContext设置外部引用它的Context。
下面看一下我们常用的几个方法,第一个是getApplicationContext方法。在自己的Activity,Service组件和Application中,调用该方法获取Context。

@Override
public Context getApplicationContext() {
    return mBase.getApplicationContext();
}

调用的是ContextWrapper的方法,最终调用实体ContextImpl的方法。它是Context的抽象方法,看一下ContextImpl的实现。

@Override
public Context getApplicationContext() {
    return (mPackageInfo != null) ?
                mPackageInfo.getApplication() : mMainThread.getApplication();
}

先从LoadedApk中获取Application,LoadedApk是空时再从ActivityThread中获取。在ContextImpl构造方法传入LoadedApk,它就不是空。LoadedApk内部的Application是在makeApplication方法创建时赋值,也就是我们创建的全局Application对象。
ActivityThread内部Application,在handleBindApplication方法初始化。

Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;

其实,它也是通过LoadedApk的makeApplication方法创建的Application。因此,getApplicationContext方法,本质是获取Application。
第二个方法是getApplication方法,在Activity和Service中,返回内部Application,该引用在attach方法初始化,是全局Application对象。因此,getApplication方法,返回Activity或Service内部的Application对象。

总结

Activity、Service和Application他们都是Context类型,内部引用真正的实现类ContextImpl。
Activity和其他两者创建ContextImpl的方法是不同的。
getApplication和getApplicationContext的区别,getApplication是Activity和Service的方法,getApplicationContext的具体实现在ContextImpl。他们都会返回Application。


其他组件的Context

ContentProvider不继承Context,内部的Context在创建对象时传入。

public ContentProvider(
            Context context,
            String readPermission,
            String writePermission,
            PathPermission[] pathPermissions) {
    mContext = context;
    mReadPermission = readPermission;
    mWritePermission = writePermission;
    mPathPermissions = pathPermissions;
}

BroadcastReceiver即不继承Context,内部也没有Context对象,在onReceive方法时传入。实现该方法时,可以使用Context的功能。

public abstract void onReceive(Context context, Intent intent);

View的Context

除了组件外,视图也和Context有关,创建视图时,他们的构造方法都会传入Context,在Activity创建一个View,传入的this代表Activity组件。

public View(Context context) {
    mContext = context;
    ...
}

View的getContext方法,当然也是返回内部的Context。在View中需要使用Context的一些方法,可能是Activity的方法,也可能是ContextImpl的实现方法。


任重而道远

相关文章

网友评论

      本文标题:和Context类关联的组件

      本文链接:https://www.haomeiwen.com/subject/qflvjqtx.html