前言
Context在开发Android应用的过程中扮演着非常重要的角色,
例如,启动一个 Activity需要使用context.startActivity方法,
将一个xml文件转换为一个View对象也需要使用Context对象,
弹窗需要context,资源获取需要,可以说没有Context,android开发
无从谈起
Applicaiton Context 和Activity Context 是否是同一个,能否混淆使用?
带着这个问题接着看;
类结构图
package android.content;
package android.app;
注意:
因为ContextImpl 和Context 不在同一个包下,用uml生成工具没能生成出来。下面的图是手动画的,应该合起来看。
Context本身是一个纯的abstract类。
ContextWrapper是对Context的一个包装而已,它的内部包含了一个 Context对象,其实对ContextWrapper的方法调用最终都是调用其中的Context对象完成的,
ContextThremeWrapper,很明显和Theme有关,所以Activity从ContextThemmWrapper继承,而 Service,application 没有主题 所从ContextWrapper继承,
ContextImpl是唯一 一个真正实现了Context中方法的类。
从上面的继承关系来看,每一个Activity就是一个Context,每一个Service就是一个Context,每一个Application就是一个Context,这也就是为什么使用Context的地方可以被Activity,Service或者Application替换了。
根据上面所介绍的,实现Context的只有Contextimpl类,其它是对context的包装,最终调用的还是的Contextimpl类,所以Activity,application,service 创建的时候肯定要创建一个ContextImpl对象,赋值给 Activity,application,service 中的context。口说无凭,跟着源码来看。
步骤一
分析startActivity()流程的,最后进入T和threadActivity中的 performLaunchActivity()方法
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);
.....
.....
}
}
进入 createBaseContextForActivity()方法
private Context createBaseContextForActivity(ActivityClientRecord r,
final Activity activity) {
ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token);
appContext.setOuterContext(activity);
Context baseContext = appContext;
final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
try {
IActivityContainer container =
ActivityManagerNative.getDefault().getEnclosingActivityContainer(r.token);
final int displayId =
container == null ? Display.DEFAULT_DISPLAY : container.getDisplayId();
if (displayId > Display.DEFAULT_DISPLAY) {
Display display = dm.getRealDisplay(displayId, r.token);
baseContext = appContext.createDisplayContext(display);
}
} catch (RemoteException e) {
}
// For debugging purposes, if the activity's package name contains the value of
// the "debug.use-second-display" system property as a substring, then show
// its content on a secondary display if there is one.
String pkgName = SystemProperties.get("debug.second-display.pkg");
if (pkgName != null && !pkgName.isEmpty()
&& r.packageInfo.mPackageName.contains(pkgName)) {
for (int displayId : dm.getDisplayIds()) {
if (displayId != Display.DEFAULT_DISPLAY) {
Display display = dm.getRealDisplay(displayId, r.token);
baseContext = appContext.createDisplayContext(display);
break;
}
}
}
return baseContext;
}
这里这是证明 activity 创建过程中会初始化 contextImpl 实现类,关于Application,service 自行查看源码,这里不过多解释。
建议直接查看 contextImpl 类,该类里面罗列了所有初始化方法。
到这里共说明了
1.application,service,activity与Context的关系。
2.application 和 activity之间是否可以替换,为什么不可以替换
3.context的类继承树
在此总结一下:
(1)Context是一个抽象类,ContextWrapper是对Context的封装,它包含一个Context类型的变 量,ContextWrapper的功能函数内部其实都是调用里面的Context类型变量完成的。 Application,Service,Activity等都是直接或者间接继承自ContextWrapper,但是并没有真正的实现其中的功 能,Application,Service,Activity中关于Context的功能都是通过其内部的Context类型变量完成的,而这个变量的 真实对象必定是ContextImpl,所以没创建一个Application,Activity,Servcice便会创建一个 ContextImpl,并且这些ContextImpl中的mPackages和mResources变量都是一样的,所以不管使用Acitivty还 是Service调用getResources得到相同的结果
(2)在一个apk中,Context的数量等于Activity个数+Service个数+application个数.
关于上面提出来问题,为什么不可以互换,很简单解释 Application 和Activity的上下文Context 不是同一个,继承树不同。Application 继承自contextWrapper,而Activity继承自ThemeWarpper. 还有Dialog弹窗和当前Activity绑定,自然不能使用Application的Context进行传值。
引用
context 解释 http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1223/2205.html