目录
  1. 1. 一、Context 的继承体系
    1. 1.1. 1.1 类图
    2. 1.2. 1.2 ContextWrapper——装饰器模式的经典应用
  2. 2. 二、ContextImpl——Context 的真正实现
    1. 2.1. 2.1 ContextImpl 的核心字段
    2. 2.2. 2.2 ContextImpl 的创建
    3. 2.3. 2.3 ActivityThread 中创建 Context
  3. 3. 三、不同类型 Context 的差异
    1. 3.1. 3.1 Application Context vs Activity Context
    2. 3.2. 3.2 getSystemService 的实现
    3. 3.3. 3.3 Service 的 Context
    4. 3.4. 3.4 ContentProvider 的 Context
  4. 4. 四、Context 的内存泄漏分析
    1. 4.1. 4.1 常见泄漏场景
  5. 5. 五、Context 在资源加载中的角色
  6. 6. 六、核心面试题
【吃透源码系列】之Context

Context 在 Android 中被描述为 “关于应用环境的全局信息接口”。它贯穿整个 Android 框架,是访问系统资源、启动组件、获取系统服务的入口。然而,Context 的继承层级、不同类型的 Context 之间的差异、以及使用不当可能导致的内存泄漏,是深入理解 Android 框架不可或缺的知识。本文深入分析 Context 的继承体系、ContextImpl 的创建过程以及各类型 Context 的差异。

一、Context 的继承体系

1.1 类图

abstract Context

abstract ContextWrapper

ContextThemeWrapper Activity

Service Application

或从 ContextImpl 角度:

Context (abstract)
├── ContextImpl (真正的实现——每种 Context 场景背后都是它)
└── ContextWrapper (装饰器基类)
├── ContextThemeWrapper (带主题的 Context)
│ └── Activity (每个 Activity 对应一个 ContextThemeWrapper)
├── Service (Service 的 Context)
└── Application (Application 的 Context)

AOSP 路径:

  • frameworks/base/core/java/android/content/Context.java
  • frameworks/base/core/java/android/content/ContextWrapper.java
  • frameworks/base/core/java/android/app/ContextImpl.java
  • frameworks/base/core/java/android/view/ContextThemeWrapper.java

1.2 ContextWrapper——装饰器模式的经典应用

ContextWrapper 是装饰器模式的典型实现,它持有一个 Context 引用(mBase),所有方法默认委托给 mBase:

// frameworks/base/core/java/android/content/ContextWrapper.java
public class ContextWrapper extends Context {
Context mBase;

public ContextWrapper(Context base) {
mBase = base;
}

// 将 mBase 指向真正的实现
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}

@Override
public ContentResolver getContentResolver() {
return mBase.getContentResolver(); // 委托给 mBase
}

@Override
public SharedPreferences getSharedPreferences(String name, int mode) {
return mBase.getSharedPreferences(name, mode);
}

@Override
public Object getSystemService(@ServiceName @NonNull String name) {
return mBase.getSystemService(name);
}

@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}
}

这一设计的精妙之处在于:Activity、Service、Application 这些类都是 ContextWrapper 的子类,但它们内部的 mBase 指向的是同一个 ContextImpl 类型。也就是说,真正干活的是 ContextImpl,而 ContextWrapper 及其子类只是提供了不同的”视角”(比如 Activity 多了主题支持)。

二、ContextImpl——Context 的真正实现

2.1 ContextImpl 的核心字段

// frameworks/base/core/java/android/app/ContextImpl.java
class ContextImpl extends Context {
final @NonNull ActivityThread mMainThread; // 主线程 ActivityThread 引用
final @NonNull LoadedApk mPackageInfo; // APK 加载信息
private @Nullable ActivityThread mUiThread; // UI 线程
private @NonNull String mBasePackageName; // 基础包名
private @NonNull String mOpPackageName; // 操作包名
private final @NonNull ResourcesManager mResourcesManager;
private @NonNull Resources mResources; // 资源访问
private @Nullable Display mDisplay; // 显示设备
private final int mFlags; // Context 创建标志
private @NonNull final UserHandle mUser; // 多用户
}

2.2 ContextImpl 的创建

不同类型的 Context 有不同的创建方式,但都通过 ContextImpl 的静态工厂方法创建:

// frameworks/base/core/java/android/app/ContextImpl.java
// 为 Application 创建 ContextImpl
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
return createAppContext(mainThread, packageInfo, null);
}

// 为 Activity 创建 ContextImpl
static ContextImpl createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken,
int displayId, Configuration overrideConfiguration) {
// Activity 的 ContextImpl 带有 activityToken(与 WMS 窗口关联)和 displayId
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, ...);
context.setResources(resourcesManager.createBaseActivityResources(
activityToken, ...));
return context;
}

2.3 ActivityThread 中创建 Context

// frameworks/base/core/java/android/app/ActivityThread.java
// 创建 Application Context
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
// ...
return appContext;
}

// 创建 Application
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) return mApplication;

Application app = (Application) clazz.newInstance();
// 创建 Application 用的 ContextImpl
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
// 绑定
app.attach(appContext);
mApplication = app;
return app;
}

三、不同类型 Context 的差异

3.1 Application Context vs Activity Context

这是最容易混淆的一组概念:

特性 Application Context Activity Context
生命周期 伴随整个应用进程 伴随 Activity 生命周期
主题支持 无(不是 ContextThemeWrapper) 有(继承 ContextThemeWrapper)
startActivity 需要 NEW_TASK flag 不需要(默认放入当前 Task)
inflate layout 使用默认主题 使用 Activity 主题
显示 Dialog 不允许(需要 Window token) 允许

3.2 getSystemService 的实现

Context 的 getSystemService 是获取系统服务的统一入口:

// frameworks/base/core/java/android/app/ContextImpl.java
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}

// frameworks/base/core/java/android/app/SystemServiceRegistry.java
final class SystemServiceRegistry {
// 静态代码块注册所有服务工厂
static {
registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,
new CachedServiceFetcher<ActivityManager>() {
@Override
public ActivityManager createService(ContextImpl ctx) {
return new ActivityManager(
ctx.getOuterContext(), // outer: Activity or Application
ctx.mMainThread.getHandler());
}
});

registerService(Context.WINDOW_SERVICE, WindowManager.class,
new CachedServiceFetcher<WindowManager>() {
@Override
public WindowManager createService(ContextImpl ctx) {
return new WindowManagerImpl(ctx.mDisplay);
}
});

registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
new CachedServiceFetcher<LayoutInflater>() {
@Override
public LayoutInflater createService(ContextImpl ctx) {
return new PhoneLayoutInflater(ctx.getOuterContext());
}
});
// ... 更多服务注册
}
}

每个系统服务在静态代码块中注册工厂,首次调用时创建,之后通过缓存返回。

3.3 Service 的 Context

// frameworks/base/core/java/android/app/Service.java
public abstract class Service extends ContextWrapper
implements ComponentCallbacks2 {

public Service() {
super(null);
}

@Override
public final void attach(Context context, ...) {
attachBaseContext(context); // 将 ContextImpl 设为 mBase
}
}

Service 直接继承 ContextWrapper(不是 ContextThemeWrapper),因此它没有主题支持,这也就是为什么你不能在 Service 中 inflate layout 并使用 Activity 主题。

3.4 ContentProvider 的 Context

ContentProvider 在 onCreate() 被调用前通过 attachInfo() 方法绑定 Context。它同样继承 ContextWrapper,生命周期与 Application 相同:

// frameworks/base/core/java/android/content/ContentProvider.java
public void attachInfo(Context context, ProviderInfo info) {
attachBaseContext(context); // 绑定的通常是 Application Context
mContext = context;
// ...
}

四、Context 的内存泄漏分析

4.1 常见泄漏场景

场景1:静态变量持有 Activity Context

public class MyManager {
private static MyManager sInstance;
private Context mContext;

private MyManager(Context context) {
mContext = context; // 如果传入的是 Activity,泄漏了!
}

public static MyManager getInstance(Context context) {
if (sInstance == null) {
sInstance = new MyManager(context);
}
return sInstance;
}
}

解法:使用 context.getApplicationContext() 或让静态变量持有 Application Context。

场景2:单例持有 Activity 引用:如 EventBus 注册了 Activity 但未解注册。

场景3:内部类/匿名类隐式持有外部类引用:如 Handler、AsyncTask 作为 Activity 的非静态内部类,它们持有对外部 Activity 的隐式引用。如果 Handler 消息延迟较长,Activity 在消息执行前被销毁,就会泄漏。

五、Context 在资源加载中的角色

ContextImpl 持有 Resources 对象,负责:

  1. 资源加载getResources().getString(R.string.xxx)getResources().getDrawable(R.drawable.xxx)
  2. AssetManager:管理 APK 内的 assets 目录文件
  3. 数据库openOrCreateDatabase() 创建 SQLiteDatabase
  4. 文件操作openFileInput()openFileOutput()
  5. SharedPreferencesgetSharedPreferences() 持久化键值对

这些操作的底层都依赖于 ContextImpl 中持有的 LoadedApk mPackageInfo 对象:

// frameworks/base/core/java/android/app/ContextImpl.java
@Override
public SharedPreferences getSharedPreferences(String name, int mode) {
return mPackageInfo.getSharedPreferences(name, mode);
}

@Override
public File getDataDir() {
return mPackageInfo.getDataDir();
}

六、核心面试题

Q1:Application Context 和 Activity Context 有什么区别?什么时候用哪个?

核心区别在于生命周期和窗口关联能力。Application Context 生命周期等于进程生命周期,适合用于单例、数据库、网络库初始化等需要全局 Context 的场景。Activity Context 带有主题和窗口令牌,适合用于 UI 相关操作(显示 Dialog、inflate layout 需要 Activity 主题、startActivity 不带 NEW_TASK 等)。一个关键原则:只要生命周期需要跟随 Activity 的资源(如 Dialog、Toast 的某些场景),就用 Activity Context;否则优先使用 Application Context 避免内存泄漏。

Q2:getApplication() 和 getApplicationContext() 返回的是同一个对象吗?

是同一个对象。getApplication() 返回的是当前进程的 Application 实例(继承自 ContextWrapper),getApplicationContext() 返回的是 Context 实例。在 Activity 或 Service 中,getApplicationContext() 返回的就是 Application 对象本身(因为 Application 实现了 Context 接口链)。从语义上说,getApplicationContext() 强调的是 “这是一个适合长时间持有的 Context”,而 getApplication() 返回的是其 Application 类型。

Q3:为什么 Activity 可以直接调用 startActivity 而不需要 FLAG_ACTIVITY_NEW_TASK?

因为 Activity 继承了 ContextThemeWrapper→ContextWrapper→Context,其内部的 ContextImpl 持有 Activity 的 token(与 WMS 的 IApplicationToken 关联),在调用 startActivity 时,系统会根据调用者的 token 自动确定目标 Activity 放入哪个 Task。而 Application Context 不持有任何 Activity 的 token,因此必须在 Intent 中显式设置 FLAG_ACTIVITY_NEW_TASK。

AOSP 核心路径参考:

  • frameworks/base/core/java/android/content/Context.java
  • frameworks/base/core/java/android/content/ContextWrapper.java
  • frameworks/base/core/java/android/app/ContextImpl.java
  • frameworks/base/core/java/android/app/SystemServiceRegistry.java
  • frameworks/base/core/java/android/view/ContextThemeWrapper.java
  • frameworks/base/core/java/android/app/ActivityThread.java
打赏
  • 微信
  • 支付宝

评论