Context 是什么?
Context 是 Android 中最核心的抽象之一,它代表了一个应用环境的全局信息。几乎所有 Android 组件都需要 Context——启动 Activity、创建 View、访问资源、打开数据库,都离不开它。
Context 的类型
整个应用进程中存在两种 Context:
- Application Context:与应用生命周期绑定。getApplicationContext() 返回。全局唯一。
- Activity Context:与 Activity 生命周期绑定。this 或 getContext()(在 Activity 中)。
// Application Context
val appCtx = context.applicationContext
// Activity Context
val activityCtx = this // 在 Activity 内部
什么时候用哪个?
| 场景 | 推荐 Context |
|---|---|
| 启动 Activity | Activity Context(需要任务栈信息) |
| 显示 Dialog | Activity Context |
| Layout Inflation | Activity Context(会使用正确主题) |
| Toast | Application Context |
| 初始化单例 | Application Context(避免内存泄漏!) |
| 启动 Service | Activity Context(Android 8.0+ 有限制) |
| 获取资源(string/color/drawable) | 两者均可 |
| 注册 BroadcastReceiver | 两者均可,取决于生命周期需求 |
常见错误
1. 单例持有 Activity Context
// ❌ 危险!Activity 无法被 GC
object UserManager {
lateinit var context: Context
}
// ✅ 正确做法
object UserManager {
lateinit var context: Application
fun init(app: Application) {
context = app
}
}
2. 使用 Application Context 显示 Dialog
// ❌ 会崩溃:Unable to add window — token null
AlertDialog.Builder(applicationContext).show()
// ✅ 使用 Activity Context
AlertDialog.Builder(this).show() // this 是 Activity
3. 静态变量持有 View 引用
// ❌ View 隐式持有 Activity Context
companion object {
var staticView: View? = null
}
Context 的继承关系
Context 是一个抽象类,有两个直接子类:ContextWrapper 和 ContextImpl。Activity、Application、Service 都继承自 ContextWrapper,内部持有一个 ContextImpl 实例作为真正的实现。
总结
记住一条黄金法则:如果引用的生命周期比 Activity 长,就用 ApplicationContext,否则用 Activity Context。这样你就能避免大部分 Context 相关的内存泄漏问题。