Android中的Context、ContextImpl和ContextWrapper详解
在Android开发里,Context、ContextImpl 和 ContextWrapper 是与上下文环境相关的重要类,下面分别介绍:
1. Context
概念
Context 是一个抽象类,它就像一个访问应用全局信息的接口。通过 Context,可以访问应用的资源、类加载器,还能进行启动 Activity、服务,发送广播等操作。在 Android 系统中,许多操作都需要 Context 才能完成。
作用
它是 Android 应用的基础,为应用提供运行时的环境信息。例如,要显示一个 Toast 提示框,就需要 Context 对象。
示例
Toast.makeText(context, "This is a toast", Toast.LENGTH_SHORT).show();
2. ContextImpl
概念
ContextImpl 是 Context 的具体实现类。它包含了大量的具体实现代码,是 Context 功能的真正执行者。ContextImpl 持有很多系统服务的引用,负责与系统底层进行交互。
作用
当调用 Context 的各种方法时,实际上最终是由 ContextImpl 来完成具体操作的。比如,启动 Activity、获取资源等操作,都是在 ContextImpl 中实现的。
创建
ContextImpl 对象通常由系统在应用启动或者组件创建时自动创建,开发者一般不需要直接创建 ContextImpl 对象。
3. ContextWrapper
概念
ContextWrapper 是一个包装类,它继承自 Context。ContextWrapper 类的主要作用是对 Context 对象进行包装,它内部持有一个 Context 对象的引用(通常是 ContextImpl 对象),并将大部分方法的调用委托给这个内部的 Context 对象。
作用
ContextWrapper 类可以让开发者在不改变原有 Context 对象的基础上,对 Context 的功能进行扩展或者修改。例如,Activity、Service 等类都继承自 ContextWrapper,它们通过 ContextWrapper 来使用 Context 的功能,并且可以在自身的类中添加额外的逻辑。
示例
public class MyContextWrapper extends ContextWrapper {
public MyContextWrapper(Context base) {
super(base);
}
// 可以在这里添加自定义的方法或者重写父类的方法
}
三者关系
Context是一个抽象类,定义了上下文环境的基本接口。ContextImpl是Context的具体实现类,负责实现Context定义的各种功能。ContextWrapper是对Context的包装类,它通过持有一个Context对象(通常是ContextImpl),并将方法调用委托给这个对象,同时允许开发者对Context的功能进行扩展。
在实际开发中,开发者一般使用 Context 类型的引用,而不需要关心具体是 ContextImpl 还是 ContextWrapper。系统会根据不同的场景创建合适的对象来完成相应的操作。
##总结
在 Android 中,一个进程可以有多个 Context,但它们的作用和生命周期有所不同。通常,进程中会有一个全局的 Application Context,其他 Activity Context、Service Context、BroadcastReceiver Context 等则根据具体组件的生命周期而创建和销毁。
虽然我们可以在应用中使用不同类型的 Context,但需要特别注意不要误用 Activity Context 或 Service Context,以避免内存泄漏问题。一般来说,推荐使用 Application Context,它的生命周期较长,不容易引起内存泄漏。
##问题:一个进程会创建多少个Context 结论: 一个进程中会创建一个Application的Context+创建的Activity+创建的Service 所以数量是:Application+当前存在的Activity+Service
1:创建Application
ActivityThread.class
private void handleBindApplication(AppBindData data) {
...
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
...
}
2:创建Activity对象
ActivityThread.class
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
ContextImpl appContext = createBaseContextForActivity(r);
...
//将contextimpl 赋值给 ContextWrapper 的mBase
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.activityConfigCallback,
r.assistToken, r.shareableActivityToken);
....
...
}
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
...
ContextImpl appContext = ContextImpl.createActivityContext( this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
...
}
ContextImpl.class
static ContextImpl createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
Configuration overrideConfiguration) {
...
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, ContextParams.EMPTY,
attributionTag, null, activityInfo.splitName, activityToken, null, 0, classLoader,
null);
...
}
3:创建Service 对象
ActivityThread.class
@UnsupportedAppUsage
private void handleCreateService(CreateServiceData data) {
...
Application app = packageInfo.makeApplicationInner(false, mInstrumentation);
...
}
LoadedApk.class
private Application makeApplicationInner(boolean forceDefaultAppClass,
Instrumentation instrumentation, boolean allowDuplicateInstances) {
...
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
...
}
4:广播(广播正常情况不创建Context)
private void handleReceiver(ReceiverData data) {
Application app = packageInfo.makeApplicationInner(false, mInstrumentation);
context = (ContextImpl) app.getBaseContext();
//默认用Application 的Context 不创建Context 实例
if (data.info.splitName != null) {
//特殊情况创建
context = (ContextImpl) context.createContextForSplit(data.info.splitName);
}
if (data.info.attributionTags != null && data.info.attributionTags.length > 0) {
final String attributionTag = data.info.attributionTags[0];
//特殊情况创建
context = (ContextImpl) context.createAttributionContext(attributionTag);
}
}