组件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的实现方法。
任重而道远
网友评论