在 MVI + Compose 项目里,ViewModel 在很大程度上“替代”了 rememberSaveable,但两者并不完全等价**。
按 结论 → 为什么 → 对照表 → 什么时候还需要 rememberSaveable → 常见误解 给一个工程级答案。
viewModel可以替代rememberSaveable
一、先给一句话结论(可以直接记)
在 MVI + Compose 架构中:
ViewModel = 主要的“可恢复状态容器”,
rememberSaveable 只负责“UI 层的临时可恢复状态”。
所以看到:
remember用得多ViewModel用得多rememberSaveable用得少
👉 这是健康、正确的现象
二、为什么 MVI + Compose 几乎不用 rememberSaveable?
关键原因只有一个:
MVI 要求:业务状态只有一个来源(Single Source of Truth)
而这个来源就是 ViewModel。
ViewModel 天然具备 rememberSaveable 的能力
| 能力 | ViewModel | rememberSaveable |
|---|---|---|
| 跨重组 | ✅ | ✅ |
| 跨配置变化 | ✅ | ✅ |
| 页面级生命周期 | ✅ | ❌(UI 层) |
| 业务可测试 | ✅ | ❌ |
| 可组合复用 | ❌ | ✅ |
👉 VM 覆盖了 rememberSaveable 的“核心诉求”
三、那 rememberSaveable 是不是“没用了”?
❌ 不是
它的定位是:
UI 层、非业务、但又需要跨配置变化的状态
四、三种状态的「正确归属」(非常重要)
我直接给一张工程分工表 👇
| 状态类型 | 放哪 | 为什么 |
|---|---|---|
| 业务状态(列表、loading、错误) | ViewModel | MVI 单一状态源 |
| UI 临时状态(Dialog、动画) | remember | 不需要恢复 |
| UI 输入状态(搜索框、Tab) | rememberSaveable / VM | 视业务而定 |
五、最典型的对比示例(一定见过)
❌ 错误(业务状态放 UI)
var list by rememberSaveable { mutableStateOf(emptyList<Item>()) }
👉 违反 MVI
✅ 正确(业务状态放 VM)
val uiState by viewModel.uiState.collectAsState()
六、那什么时候该用 rememberSaveable?(真实工程场景)
✅ 场景 1:搜索框(未提交)
var query by rememberSaveable { mutableStateOf("") }
为什么不放 VM?
- 输入频繁
- 不一定是业务意图
- 不需要发 Intent
✅ 场景 2:Tab 选中索引(纯 UI)
var selectedTab by rememberSaveable { mutableStateOf(0) }
✅ 场景 3:滚动位置
Compose 内部其实大量用 rememberSaveable
val listState = rememberLazyListState()
(内部就是 saveable)
七、一个非常常见的误解(一定要避开)
❌ 错误理解
“rememberSaveable 就是 remember + ViewModel”
✅ 正确理解
rememberSaveable = UI 层的 SavedInstanceState
ViewModel = 架构层的状态容器
八、为什么团队“刻意少用 rememberSaveable”?
工程原因:
- Bundle 序列化有成本
- 类型受限
- 容易滥用
- 容易把业务状态藏到 UI
👉 优秀的 MVI 项目都会克制使用
九、这个观察说明了什么?(非常重要)
说明已经在:
- 看真实项目
- 看状态的“归属”
- 看架构设计意图
👉 这已经不是“学 Compose API”,而是在理解 Compose + 架构的协作方式
十、送一句工程级总结(建议记住)
ViewModel 负责“该不该恢复”,
rememberSaveable 负责“怎么恢复 UI 体验”。
2112

被折叠的 条评论
为什么被折叠?



