跟进 定义 → 关系 → 触发时机 → 正确使用模式 → 常见坑 → MVI 场景 来讲清楚。
一、先给一句话结论
DisposableEffect是"生命周期作用域"
onDispose是"离开该作用域时的清理回调"
👉 两者不是同级概念
二、先把概念分清楚(非常重要)
1️⃣ DisposableEffect 是什么?
kotlin
DisposableEffect(key) {
// 初始化 / 注册逻辑
onDispose {
// 清理逻辑
}
}
它本身代表:
"当这个 Composable 进入组合时执行一次,当离开或 key 变化时执行清理"
2️⃣ onDispose 是什么?
kotlin
onDispose {
// 清理资源
}
它只是一个回调函数:
"当 DisposableEffect 被销毁时执行"
👉 onDispose 永远只能写在 DisposableEffect 里
三、生命周期触发时机(核心)
我们用一张表直接说明 👇
| 事件 | DisposableEffect | onDispose |
|---|---|---|
| 首次进入组合 | 执行 effect 代码 | ❌ |
| 普通重组 | ❌ 不执行 | ❌ |
| key 发生变化 | ❌(旧的 effect 销毁) | ✅ |
| 离开组合 | ❌ | ✅ |
👉 onDispose 的触发条件 = effect 生命周期结束
四、一个最直观的时间线(建议你在脑子里记住)
text
Composable 进入组合
↓
DisposableEffect 执行(注册)
↓
多次重组(不影响)
↓
Composable 离开组合 / key 改变
↓
onDispose 执行(清理)
五、标准使用模式(99% 场景)
✅ 模板写法(直接记)
kotlin
DisposableEffect(key) {
// 1️⃣ 注册 / 初始化
val resource = registerSomething()
onDispose {
// 2️⃣ 注销 / 清理
unregister(resource)
}
}
典型场景 1:注册监听
kotlin
DisposableEffect(lifecycle) {
val observer = LifecycleEventObserver { _, event ->
Log.d("Lifecycle", "$event")
}
lifecycle.addObserver(observer)
onDispose {
lifecycle.removeObserver(observer)
}
}
典型场景 2:系统资源(Receiver)
kotlin
DisposableEffect(Unit) {
val receiver = MyReceiver()
context.registerReceiver(receiver, filter)
onDispose {
context.unregisterReceiver(receiver)
}
}
六、key 的作用(非常关键)
kotlin
DisposableEffect(userId) { ... }
行为规则:
-
userId不变 → effect 一直存在 -
userId变化 →- 先调用旧的
onDispose - 再执行新的 DisposableEffect
- 先调用旧的
👉 key = 生命周期边界
七、为什么不用 LaunchedEffect 来做这些?
| 场景 | LaunchedEffect | DisposableEffect |
|---|---|---|
| 异步任务 | ✅ | ❌ |
| 协程自动取消 | ✅ | ❌ |
| 资源注册释放 | ❌ | ✅ |
| 同步监听 | ❌ | ✅ |
👉 DisposableEffect 解决的是"资源对称性问题"
八、一个非常常见的反模式(一定要避开)
❌ 错误写法:只注册,不清理
kotlin
DisposableEffect(Unit) {
lifecycle.addObserver(observer)
}
👉 Lint 都会直接报警
❌ 错误写法:在 onDispose 里做初始化
kotlin
DisposableEffect(Unit) {
onDispose {
initSomething() // ❌
}
}
九、在 MVI + Compose 中的正确定位
Composable 只负责 UI 生命周期
- ViewModel:业务生命周期
- DisposableEffect:UI 资源生命周期
示例:绑定 UI 层事件
kotlin
DisposableEffect(Unit) {
viewModel.bindUi()
onDispose {
viewModel.unbindUi()
}
}
十、再给一句"工程级总结"(很重要)
DisposableEffect 是"声明式生命周期",
onDispose 是"它的 onDestroy 回调"。