1. ViewModel与状态持久化概述
1.1 为什么需要持久化
Android 应用在运行过程中会面临多种状态丢失的风险:
- 配置变更(如屏幕旋转、语言切换):Activity 重建,默认 ViewModel 可存活,但若绑定 Activity 作用域不合理仍可能丢失。
- 进程终止(系统回收、用户主动杀进程、低内存杀进程):ViewModel 实例及其内存数据全部丢失。
- 系统重建(如
Don't keep activities开启时):Activity 和 ViewModel 可能被重建。
如果应用只依赖 ViewModel 的内存缓存,没有持久化机制,用户在流转中填写的表单、购物车内容、草稿等关键数据就会丢失,造成极差的用户体验。因此,必须将跨生命周期、跨进程的数据持久化到磁盘。
1.2 ViewModel 生命周期与状态丢失
ViewModel 的生命周期由 ViewModelStoreOwner(如 Activity / Fragment)的 Lifecycle 管理。在配置变更时 ViewModel 实例被保留(不调用 onCleared());但进程被系统销毁回收时,ViewModel 会随进程一起消失。下图箭头标注了两次典型的丢失窗口:
- 配置变更后:ViewModel 存活,不会丢失。
- 进程终止:
onCleared()不会被调用,所有val、LiveData数据全部丢失。 - 用户主动返回/退出:Activity 真正 finish 后,ViewModel 调用
onCleared(),若未持久化则丢失。
⚠️ 易错点:许多开发者误以为 ViewModel 能“永久保存”数据,但实际上它只能抵抗配置变更,对进程级销毁无能为力。任何需要跨 Activity 重建、跨 App 重启保留的数据都必须使用持久化方案。
1.3 持久化策略概览
Android 官方及社区提供了多种持久化方案,下表从持久化范围、恢复时机、复杂度三个维度进行比较:
| 策略 | 持久化范围 | 恢复时机 | 复杂度 | 典型场景 |
|---|---|---|---|---|
| SavedStateHandle | Bundle 序列化(<1MB) | ViewModel 重建时自动注入 | 低 | 表单输入、UI 状态 |
| Room 数据库 | SQLite 表(无大小限制) | 应用启动或 ViewModel 初始化 | 高 | 结构化业务数据、列表缓存 |
| DataStore | 键值对 / Protobuf | 异步首次读取 | 中 | 用户偏好设置、简单标记 |
| SharedPreferences | 键值对(内存IO) | 同步读 / 异步读 | 低 | 少量配置(不推荐新项目) |
💡 选型建议:对于简单 UI 状态首选
SavedStateHandle;对于复杂业务数据使用 Room;避免在 ViewModel 中直接使用 SharedPreferences 做复杂结构化存储,容易引发 ANR。
// 添加 SavedStateHandle 依赖(build.gradle)
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1"
下面的 SVG 流程总结了 ViewModel 生命周期中的状态丢失点及持久化策略的介入时机:
🎯 核心要点:ViewModel 的生命周期介于 Activity 与进程之间;
● 配置变更 → ViewModel 存活,无需持久化
● 进程终止 → 状态丢失,必须使用持久化策略
● 持久化策略的选择应权衡数据规模、恢复速度和开发效率。
● 配置变更 → ViewModel 存活,无需持久化
● 进程终止 → 状态丢失,必须使用持久化策略
● 持久化策略的选择应权衡数据规模、恢复速度和开发效率。