[Android 从零到一] ViewModel 源码机制与进程重建恢复:从 ViewModelStore 到 SavedStateRegistry 的完整链路
ViewModel 是 Android Jetpack 架构组件的核心,它不仅能在配置变更(如屏幕旋转)时保留数据,还能与 SavedState 机制配合,在进程重建后恢复状态。本文从源码层面拆解 ViewModel 的存储、恢复、与 SavedState 的集成机制,帮助你真正理解它的工作原理。
---
ViewModel 的生命周期为什么比 Activity 长?
ViewModelStore:ViewModel 的容器
ViewModel 实例并不直接存储在 Activity 或 Fragment 中,而是放在一个叫 `ViewModelStore` 的容器里。这个容器本质上是一个 `HashMap
// androidx.lifecycle.ViewModelStore class ViewModelStore { private val map = HashMap() fun put(key: String, viewModel: ViewModel) { val oldViewModel = map.put(key, viewModel) oldViewModel?.onCleared() }
operator fun get(key: String): ViewModel? = map[key]
fun clear() { for (vm in map.values) { vm.onCleared() } map.clear() } }
ComponentActivity 如何持有 ViewModelStore
`ComponentActivity` 实现了 `ViewModelStoreOwner` 接口,它会在配置变更时保留 `ViewModelStore`:
// androidx.activity.ComponentActivity public class ComponentActivity : ... , ViewModelStoreOwner { private var viewModelStore: ViewModelStore? = nulloverride fun getViewModelStore(): ViewModelStore { if (viewModelStore == null) { // 1. 尝试从 NonConfigurationInstance 恢复 val nc = lastNonConfigurationInstance as? NonConfigurationInstances viewModelStore = nc?.viewModelStore ?: ViewModelStore() } return viewModelStore!! }
override fun onRetainNonConfigurationInstance(): Any? { val viewModelStore = viewModelStore ?: return null return NonConfigurationInstances().apply { this.viewModelStore = viewModelStore } } }
当屏幕旋转时: 1. 系统调用 `onRetainNonConfigurationInstance()`,Activity 把 `ViewModelStore` 包装成 `NonConfigurationInstances` 返回 2. 旧 Activity 销毁,但 `ViewModelStore` 被系统保存在内存中 3. 新 Activity 创建,调用 `getViewModelStore()` 时从 `lastNonConfigurationInstance` 恢复
这样 ViewModel 实例就跨越了 Activity 的重建,数据不丢失。
---
ViewModel 如何被创建?ViewModelProvider 的工厂机制
你在代码中这样获取 ViewModel:
val viewModel: MyViewModel by viewModels()
// 或
val viewModel = ViewModelProvider(this)[MyViewModel::class.java]
ViewModelProvider 的核心逻辑
// androidx.lifecycle.ViewModelProvider class ViewModelProvider( private val store: ViewModelStore, private val factory: Factory ) { operator funget(modelClass: Class ): T { val canonicalName = modelClass.canonicalName ?: throw IllegalArgumentException() return get("$DEFAULT_KEY:$canonicalName", modelClass) } operator fun
get(key: String, modelClass: Class ): T { // 1. 先从 ViewModelStore 查 val cached = store[key] if (modelClass.isInstance(cached)) { return cached as T }
// 2. 没有则用 Factory 创建 val viewModel = factory.create(modelClass) store.put(key, viewModel) return viewModel } }
Factory 的默认实现
如果你没有自定义 Factory,`ComponentActivity` 会提供默认的 `SavedStateViewModelFactory`:
// androidx.activity.ComponentActivity
override fun getDefaultViewModelProviderFactory(): ViewModelProvider.Factory {
return SavedStateViewModelFactory(
application,
this,
intent?.extras
)
}
这个 Factory 做了两件事: 1. 支持无参构造的 ViewModel 2. 支持带 `SavedStateHandle` 参数的 ViewModel
---
SavedState 机制如何与 ViewModel 集成?
SavedStateRegistry:状态存储的核心
`ComponentActivity` 实现了 `SavedStateRegistryOwner` 接口,它内部持有一个 `SavedStateRegistry`:
// androidx.savedstate.SavedStateRegistry class SavedStateRegistry { private val components = mutableMapOf() fun registerSavedStateProvider(key: String, provider: SavedStateProvider) { components[key] = provider }
fun consumeRestoredStateForKey(key: String): Bundle? { // 从 savedState 中取出对应 key 的数据 }
fun performSave(outBundle: Bundle) { // 遍历所有 SavedStateProvider,调用 saveState() 存入 outBundle components.forEach { (key, provider) -> outBundle.putBundle(key, provider.saveState()) } } }
SavedStateHandle 的工作原理
`SavedStateHandle` 是一个可观察的数据容器,它的数据来自 `SavedStateRegistry`:
// androidx.lifecycle.SavedStateHandle class SavedStateHandle(initialState: Map) { private val regular = mutableMapOf () private val savedStateProvider = SavedStateProvider { // 保存时,把 regular 转为 Bundle Bundle().apply { regular.forEach { (key, value) -> putValue(key, value) } } } operator fun
get(key: String): T? = regular[key] as? T operator fun
set(key: String, value: T?) { regular[key] = value }
fun getLiveData(key: String): MutableLiveData { // 返回一个 LiveData,底层数据存在 regular 中 } }
SavedStateViewModelFactory 的创建逻辑
// androidx.lifecycle.SavedStateViewModelFactory override funcreate(key: String, modelClass: Class ): T { // 1. 从 SavedStateRegistry 读取之前保存的 Bundle val savedState = savedStateRegistry.consumeRestoredStateForKey(key) // 2. 创建 SavedStateHandle val handle = SavedStateHandle.createHandle(savedState, defaultArgs)
// 3. 注册 SavedStateProvider,在 onSaveInstanceState 时自动保存 savedStateRegistry.registerSavedStateProvider(key) { handle.savedStateProvider().saveState() }
// 4. 反射找到带 SavedStateHandle 参数的构造函数 val constructor = modelClass.getConstructor(SavedStateHandle::class.java) return constructor.newInstance(handle) }
完整的保存与恢复流程
保存阶段(Activity.onSaveInstanceState):
ComponentActivity.onSaveInstanceState()
→ SavedStateRegistry.performSave(outBundle)
→ 遍历所有 SavedStateProvider
→ SavedStateHandle.savedStateProvider.saveState()
→ 把 regular 中的数据打包成 Bundle
→ 存入 outBundle["androidx.lifecycle.BundlableSavedStateRegistry.key"]
恢复阶段(Activity.onCreate):
ComponentActivity.onCreate(savedInstanceState) → SavedStateRegistry.performRestore(savedInstanceState) → 从 Bundle 中读取 "androidx.lifecycle.BundlableSavedStateRegistry.key" → 缓存到 SavedStateRegistry 的内部 Map
ViewModelProvider.get(MyViewModel::class.java) → SavedStateViewModelFactory.create() → savedStateRegistry.consumeRestoredStateForKey(key) → 取出之前缓存的 Bundle → 创建 SavedStateHandle(restoredState) → 用反射调用 MyViewModel(handle) 构造函数
---
为什么配置变更和进程重建的恢复机制不同?
| 场景 | 恢复方式 | 数据来源 | 限制 |
| ------ | --------- | --------- | ------ |
| 配置变更(屏幕旋转) | `ViewModelStore` 直接恢复 | 内存中的对象 | 无限制,所有 ViewModel 字段都保留 |
| 进程重建(系统杀死) | `SavedStateHandle` 恢复 | `onSaveInstanceState` 的 Bundle | 只能存基本类型、Parcelable、Serializable |
典型的混合使用场景
class UserDetailViewModel( private val handle: SavedStateHandle ) : ViewModel() {// 1. 轻量状态:用 SavedStateHandle,支持进程重建恢复 val userId: String? = handle["user_id"]
// 2. 重量数据:只存内存,配置变更时保留,进程重建时需重新加载 private val _userDetail = MutableLiveData
() val userDetail: LiveData = _userDetail init { userId?.let { loadUserDetail(it) } }
fun loadUserDetail(id: String) { handle["user_id"] = id // 保存到 SavedStateHandle viewModelScope.launch { _userDetail.value = repository.getUser(id) } } }
---
ViewModel 什么时候真正销毁?onCleared() 的调用时机
`ViewModel.onCleared()` 会在以下情况被调用:
1. Activity finish 时
// androidx.activity.ComponentActivity
override fun onDestroy() {
super.onDestroy()
if (!isChangingConfigurations) {
// 只有真正销毁时才清理 ViewModelStore
viewModelStore?.clear()
}
}
2. Fragment 真正移除时
// androidx.fragment.app.FragmentManager
fun performDestroy(f: Fragment) {
if (f.mViewModelStore != null) {
f.mViewModelStore.clear()
}
}
3. Navigation 返回时
当你用 `NavController.popBackStack()` 离开一个 Fragment 时,它的 ViewModel 会被清理,除非你使用了 `by navGraphViewModels()` 共享作用域。
---
实战建议
1. 合理选择状态存储方式
class MyViewModel(private val handle: SavedStateHandle) : ViewModel() {// ❌ 进程重建后丢失 private var tempFlag = false
// ✅ 进程重建后恢复 var savedFlag: Boolean get() = handle["flag"] ?: false set(value) { handle["flag"] = value }
// ✅ 配置变更时保留,进程重建时需重新加载 private val _heavyData = MutableLiveData() val heavyData: LiveData = _heavyData }
2. 不要在 SavedStateHandle 中存大对象
// ❌ Bitmap 不能序列化,且太大 handle["avatar"] = bitmap
// ✅ 只存 URI,用时再加载 handle["avatar_uri"] = uri.toString()
3. 用 AbstractSavedStateViewModelFactory 支持自定义依赖
如果你的 ViewModel 既需要 SavedStateHandle,又需要其他依赖(如 Repository),可以自定义 Factory:
class MyViewModelFactory( private val repository: UserRepository, owner: SavedStateRegistryOwner, defaultArgs: Bundle? ) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
override funcreate( key: String, modelClass: Class , handle: SavedStateHandle ): T { return MyViewModel(repository, handle) as T } }
4. 测试 ViewModel 的 SavedState 恢复逻辑
@Test fun `test SavedStateHandle restores user ID`() { val savedState = bundleOf("user_id" to "123") val handle = SavedStateHandle(savedState) val viewModel = UserViewModel(handle)
assertEquals("123", viewModel.userId) }
---
总结
- ViewModelStore 在配置变更时由系统在内存中保留,让 ViewModel 实例跨越 Activity 重建
- SavedStateRegistry 在进程重建时通过 `onSaveInstanceState` 持久化轻量状态
- SavedStateHandle 是连接两者的桥梁,既支持配置变更,又支持进程重建
- onCleared() 只在真正销毁时调用(finish、返回栈弹出、进程退出),配置变更时不会调用
- 哪些数据需要存在 SavedStateHandle(轻量状态)
- 哪些数据可以只放在 ViewModel 字段(重量数据)
- 什么时候需要重新加载数据(进程重建后)
理解这些机制,你就能准确判断:
ViewModel + SavedState 的组合,让 Android 页面状态管理既灵活又可靠。

浙公网安备 33010602011771号