关于Context和ContextImpl还有ContextWrapper的关系
1.Context和ContextImpl还有ContextWrapper的关系
图一.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吗?