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 官方及社区提供了多种持久化方案,下表从持久化范围、恢复时机、复杂度三个维度进行比较:

策略持久化范围恢复时机复杂度典型场景
SavedStateHandleBundle 序列化(<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 持久化决策流程 ViewModel 创建 配置变更(旋转) 进程终止(杀进程) 内存状态丢失 选择持久化策略 SavedStateHandle / Room / DataStore 回到目标状态 说明 配置变更不丢失 进程终止才丢失
🎯 核心要点:ViewModel 的生命周期介于 Activity 与进程之间;
● 配置变更 → ViewModel 存活,无需持久化
● 进程终止 → 状态丢失,必须使用持久化策略
● 持久化策略的选择应权衡数据规模、恢复速度和开发效率。