Jetpack Compose 状态生命周期说明文档
(remember / retain / rememberSaveable / rememberSerializable)
本文基于 Google 官方 Compose 文档
State lifespans in Compose
一、为什么需要这些 API?
Compose 中的状态,默认是短命的:
kotlin
val x = 0
- 每次重组都会重新执行
- Activity 重建后一定丢失
- 进程被杀后完全消失
为了解决 "状态应该活多久" 的问题,Compose 提供了不同层级的状态保存机制。
二、状态生命周期总览(先看结论)
| API | 跨重组 | 跨配置变化(旋转等) | 进程被杀后恢复 | 核心特点 |
|---|---|---|---|---|
remember |
✅ | ❌ | ❌ | 只对抗重组 |
retain |
✅ | ✅ | ❌ | 保持同一个实例 |
rememberSaveable |
✅ | ✅ | ✅ | 基于 SavedState |
rememberSerializable |
✅ | ✅ | ✅ | 基于 kotlinx.serialization |
三、remember
1️⃣ 定义
在当前 Composition 中缓存一个值,避免重组时重新创建
kotlin
val state = remember { mutableStateOf(0) }
2️⃣ 生命周期
- ✅ 重组(Recomposition)
- ❌ Activity 重建
- ❌ 进程被杀
Composable 离开 Composition,状态就消失
3️⃣ 典型使用场景
✅ UI 临时状态
✅ 动画状态
✅ 只和当前 Composable 有关的状态
kotlin
@Composable
fun ExpandableCard() {
var expanded by remember { mutableStateOf(false) }
...
}
4️⃣ 不要用在这里
❌ 用户输入
❌ Tab 选中状态
❌ 滚动位置
❌ 需要跨旋转保存的状态
四、retain(官方 API,容易被忽略)
1️⃣ 定义
在配置变化时保留同一个对象实例(不做序列化)
kotlin
val player = retain {
ExoPlayer.Builder(appContext).build()
}
2️⃣ 生命周期
- ✅ 重组
- ✅ Activity 重建(旋转等)
- ❌ 进程被杀
⚠️ 不会保存到 Bundle,不会 restore
3️⃣ retain 的核心语义(非常重要)
"保持同一个实例(===)"
- 不重新创建
- 不做序列化
- 类似
onRetainNonConfigurationInstance
4️⃣ 适合的对象类型
✅ 不能序列化的大对象
✅ 播放器(ExoPlayer)
✅ 缓存、控制器、引擎
✅ Flow / Channel / 协程相关对象
5️⃣ retain 的铁律(必须遵守)
❌ 不能引用 Activity / Fragment / View / Lifecycle
kotlin
// ❌ 错误
retain { MyManager(activity) }
kotlin
// ✅ 正确
retain { MyManager(applicationContext) }
五、rememberSaveable
1️⃣ 定义
在 remember 的基础上,把状态保存到 SavedStateRegistry
kotlin
var count by rememberSaveable { mutableStateOf(0) }
2️⃣ 生命周期
- ✅ 重组
- ✅ 配置变化
- ✅ 进程被杀后恢复
3️⃣ 默认支持的数据类型
Int/Long/BooleanStringParcelableSerializable
4️⃣ 自定义对象(Saver)
kotlin
data class UiState(val a: Int, val b: Int)
val state = rememberSaveable(
saver = listSaver(
save = { listOf(it.a, it.b) },
restore = { UiState(it[0], it[1]) }
)
) {
UiState(0, 0)
}
5️⃣ 典型使用场景
✅ 用户输入
✅ Tab / 页面选中状态
✅ 滚动位置
✅ 表单数据
六、rememberSerializable(官方 API)
1️⃣ 定义
专门为 kotlinx.serialization 提供的 rememberSaveable 变体
kotlin
@Serializable
data class UserUiState(
val name: String,
val age: Int
)
val state = rememberSerializable {
UserUiState("", 0)
}
2️⃣ 生命周期
- ✅ 重组
- ✅ 配置变化
- ✅ 进程被杀后恢复
3️⃣ 和 rememberSaveable 的区别
| 对比点 | rememberSaveable | rememberSerializable |
|---|---|---|
| 保存机制 | Bundle + Saver | kotlinx.serialization |
| 是否写 Saver | 可能需要 | 不需要 |
| 适合对象 | Android 风格 | 纯 Kotlin 数据 |
4️⃣ 适合的项目类型
✅ MVI / Redux
✅ 纯数据 UI State
✅ 跨平台 / KMP 项目
七、官方推荐使用顺序(经验法则)
UI 状态选择优先级
ViewModel(业务状态)
↓
rememberSaveable / rememberSerializable(用户状态)
↓
retain(不可序列化的长期对象)
↓
remember(临时 UI 状态)
八、你作为 Android 工程师应该怎么用?
常见场景对照表
| 场景 | 正确选择 |
|---|---|
| 动画展开 / 收起 | remember |
| Tab 选中 | rememberSaveable |
| 输入框内容 | rememberSaveable |
| 播放器 / 引擎 | retain |
| UI State(data class) | rememberSerializable |
| 网络数据 | ViewModel |
九、一句话总结(定锚点)
- remember:对抗重组
- retain:保持实例,跨配置
- rememberSaveable:SavedState
- rememberSerializable:序列化 UI State