ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Activity 的状态改变、状态保存

2026/8/4 16:07:59 拓冰建站 浏览量
Activity 的状态改变、状态保存

Android 页面状态丢失主要来自两类情况:

  1. 配置变更导致页面重建:
    例如:
  • 屏幕旋转
  • 深色模式切换
  • 语言切换
  • 屏幕尺寸变化
旧 Activity 被销毁 ↓ 创建新的 Activity 实例

但应用进程一般还活着。
2. 应用进程被系统回收
例如应用进入后台后,系统因内存不足杀死应用进程:

Activity、ViewModel、Application 全部消失 ↓ 用户重新返回应用 ↓ 系统重新创建进程和 Activity

一、onSaveInstanceState 与 ViewModel 的本质区别

它们最大的区别在于,应对“配置变更”和“系统发起的进程死亡”时的处理方式不同。

对比维度onSaveInstanceStateViewModel
核心目的保存少量、临时的 UI 状态,例如滚动位置、输入框文字、选中的 ID持有并管理界面相关的数据,例如网络请求结果、用户列表和页面状态
生命周期范围保存的状态由系统 Saved State 机制管理,不依赖旧 Activity 实例继续存活跟随 Activity、Fragment 等 ViewModelStoreOwner 的作用域
配置变更时✅ 旧 Activity 销毁,保存的数据通过 Bundle 传递给新 Activity✅ ViewModel 实例保留,新 Activity 获取同一个实例
系统发起进程死亡时✅ 可恢复之前保存的少量状态❌ ViewModel 及内存数据全部丢失
数据存储方式数据转为 Bundle 支持类型,交由系统持久化管理存储在当前应用进程堆内存中
代码职责通常由 Activity / Fragment / View 执行保存与恢复逻辑页面数据、业务逻辑可从 Activity/Fragment 剥离解耦
数据量限制必须轻量;受 Binder 缓冲区限制(约1MB,进程共享),禁止存放大对象无 Bundle 序列化限制,但受应用最大堆内存约束

二、这就引出了“尴尬的灰色地带”

想象一个场景:用户在购物车页面,ViewModel里存了十几个商品对象,用户按下 Home 键切到后台。此时系统内存不足,杀掉了应用进程

  • ViewModel被杀死,商品数据丢失(因为它在内存里)。
  • onSaveInstanceState虽然幸存,但商品列表里的图片、大文本等数据量太大,根本不适合序列化进 Bundle,强行存会崩溃。

所以,单纯的ViewModel无法应对“进程死亡”,而onSaveInstanceState又不适合存稍大一点、复杂的业务数据。这导致开发者往往需要两头写代码ViewModel存大对象,onSaveInstanceState存小标记(比如购物车ID),重建时用 ID 去数据库或网络重新拉取。

这种“两头对接”的方式非常繁琐且容易出错。


三、SavedStateHandle:破局的“桥梁”

SavedStateHandle正是为了解决上述痛点而生的。它本质上是一个专属于ViewModel的“保险箱”,充当了ViewModel和系统onSaveInstanceState机制之间的桥梁。

它的核心作用是:让 ViewModel 拥有“进程被强杀后自动恢复”的能力,而无需在 Activity/Fragment 中写任何序列化或恢复代码。

1. 它是如何工作的?

当系统准备销毁进程时,SavedStateHandle会自动将其内部存储的 Key-Value 数据写入系统的Bundle(即走的onSaveInstanceState通道)。当进程重建时,系统自动将这个 Bundle 恢复并重新注入到新的ViewModel实例中。

关键点SavedStateHandle内部有一个SavedStateRegistry与系统挂钩,这个过程对开发者完全透明。

2. 它如何简化开发?

你不再需要在 Activity 中重写onSaveInstanceState()去保存某个 ID,再在onCreate里取出来传给 ViewModel。所有状态保存和恢复的逻辑,现在都统一写在 ViewModel 内部了。

3. 典型用法示例

假设有一个用户详情页,只需要保存一个userId

classUserViewModel(privatevalsavedStateHandle:SavedStateHandle):ViewModel(){// 方式一:直接读写funsaveUserId(id:String){savedStateHandle["user_id"]=id}fungetUserId():String?{returnsavedStateHandle["user_id"]}// 方式二:使用委托(最简洁,推荐)varuserId:StringbysavedStateHandle.string("user_id","default_id")// 方式三:配合 LiveData 使用,界面观察变化valuserName:MutableLiveData<String>=savedStateHandle.getLiveData("user_name","DefaultName")}

当界面因内存不足被重建时,这个userId会自动恢复,ViewModel拿到它后直接发起网络请求获取新的用户详情,界面无缝刷新。

4. 使用它的核心约束
  • 轻量级:它依然是走 Bundle 序列化的通道,默认受 1MB 大小限制。存列表或图片依然不合适(存 ID,再重新拉取才是正解)。
  • 不可持久化:用户主动从最近任务划掉应用,或应用被卸载,数据永久丢失(它只保进程死亡,不保应用彻底关闭)。

四、一句话总结三者的关系

  • onSaveInstanceState是系统的“序列化仓库”(只存小东西,且必须由 Activity 亲自管理)。
  • ViewModel是内存中的“大型数据仓库”(配置变更时不怕,但进程死亡就完蛋)。
  • SavedStateHandle“ViewModel 随身携带的钥匙”,让 ViewModel 可以随时把关键的小数据锁进系统的“序列化仓库”里,让 ViewModel 同时具备了抵抗进程死亡的能力,且代码高度内聚,无需界面层参与。