onSaveInstanceState() 和 ViewModel 在数据保存能力差异
一、设计目标差异
维度 | onSaveInstanceState() | ViewModel |
---|---|---|
核心目的 | 保存 瞬态 UI 状态(如用户输入、滚动位置),应对进程意外终止或配置变更。 | 管理 业务逻辑相关数据,在配置变更时保留数据,避免重复加载或计算。 |
数据范围 | 仅限轻量级、可序列化的键值对(如 String 、Int )。 | 支持任意类型对象(如 List 、Bitmap 、自定义模型类)。 |
生命周期 | 数据仅在进程被系统回收时保留(如内存不足),进程重启后数据丢失。 | 数据在配置变更(如屏幕旋转)时保留,且与 UI 控制器(Activity/Fragment)解耦。 |
二、底层实现机制对比
1. 数据存储位置
-
onSaveInstanceState()
- 数据通过
Bundle
序列化后存储在 系统进程内存(ActivityRecord
)中,通过 Binder 机制跨进程传输。 - 限制:Binder 传输缓冲区大小为 1MB,超过会抛出
TransactionTooLargeException
。
- 数据通过
-
ViewModel
- 数据保存在 应用进程内存 的
ViewModelStore
中,与 UI 控制器生命周期绑定。 - 优势:无序列化限制,可存储大对象(如网络请求结果、复杂数据模型)。
- 数据保存在 应用进程内存 的
2. 序列化与反序列化
-
onSaveInstanceState()
- 强制使用
Parcelable
或Serializable
接口,序列化/反序列化过程耗时,可能阻塞主线程。 - 示例:保存
Bitmap
需转换为byte[]
,导致内存占用和性能问题。
- 强制使用
-
ViewModel
- 数据直接存储在内存中,无需序列化。
- 支持复杂对象直接赋值(如
LiveData<List<Item>>
),读写效率高。
3. 生命周期管理
-
onSaveInstanceState()
- 触发时机:系统可能销毁 Activity 时(如按 HOME 键、启动新 Activity)。
- 局限性:无法处理进程被系统终止的情况(如后台进程被回收)。
-
ViewModel
- 生命周期与 UI 控制器绑定,仅在配置变更时保留数据。
- 通过
onCleared()
方法主动释放资源,避免内存泄漏。
三、性能与适用场景
场景 | onSaveInstanceState() | ViewModel |
---|---|---|
配置变更 | 数据自动保存与恢复,但受限于序列化性能。 | 数据直接保留,无需序列化,响应更快。 |
进程终止 | 数据可持久化到磁盘(通过 Bundle ),但大小受限。 | 数据随进程终止而丢失,需结合持久化存储(如 Room)实现长期保存。 |
复杂数据操作 | 不适合频繁读写或大对象操作。 | 支持异步加载(如 LiveData + ViewModel ),适合分页列表、网络请求状态管理。 |
四、混合使用策略
1. 分工协作示例
-
ViewModel
:保存分页列表数据(LiveData<PagedList<Item>>
)。 -
onSaveInstanceState()
:保存当前页码和搜索关键词(Bundle.putString("search_key", query)
)。
2. 代码实现
// ViewModel 保存分页数据
class PagingViewModel : ViewModel() {val items = MutableLiveData<PagedList<Item>>()
}// Activity 保存瞬态状态
override fun onSaveInstanceState(outState: Bundle) {super.onSaveInstanceState(outState)outState.putString("search_query", viewModel.currentQuery)outState.putInt("current_page", viewModel.currentPage)
}