首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >ViewModel 源码机制与进程重建恢复:从 ViewModelStore 到 SavedStateRegistry 的完整链路

ViewModel 源码机制与进程重建恢复:从 ViewModelStore 到 SavedStateRegistry 的完整链路

原创
作者头像
hunter android
发布2026-08-10 11:27:06
发布2026-08-10 11:27:06
550
举报

ViewModel 是 Android Jetpack 架构组件的核心,它不仅能在配置变更(如屏幕旋转)时保留数据,还能与 SavedState 机制配合,在进程重建后恢复状态。本文从源码层面拆解 ViewModel 的存储、恢复、与 SavedState 的集成机制,帮助你真正理解它的工作原理。

---

ViewModel 的生命周期为什么比 Activity 长?

ViewModelStore:ViewModel 的容器

ViewModel 实例并不直接存储在 Activity 或 Fragment 中,而是放在一个叫 `ViewModelStore` 的容器里。这个容器本质上是一个 `HashMap<String, ViewModel>`:

代码语言:javascript
复制
// androidx.lifecycle.ViewModelStore
class ViewModelStore {
    private val map = HashMap<String, ViewModel>()

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`:

代码语言:javascript
复制
// androidx.activity.ComponentActivity
public class ComponentActivity : ... , ViewModelStoreOwner {
    private var viewModelStore: ViewModelStore? = null

override 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:

代码语言:javascript
复制
val viewModel: MyViewModel by viewModels()
// 或
val viewModel = ViewModelProvider(this)[MyViewModel::class.java]

ViewModelProvider 的核心逻辑

代码语言:javascript
复制
// androidx.lifecycle.ViewModelProvider
class ViewModelProvider(
    private val store: ViewModelStore,
    private val factory: Factory
) {
    operator fun  get(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`:

代码语言:javascript
复制
// 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`:

代码语言:javascript
复制
// androidx.savedstate.SavedStateRegistry
class SavedStateRegistry {
    private val components = mutableMapOf<String, SavedStateProvider>()

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`:

代码语言:javascript
复制
// androidx.lifecycle.SavedStateHandle
class SavedStateHandle(initialState: Map<String, Any?>) {
    private val regular = mutableMapOf<String, Any?>()
    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 的创建逻辑

代码语言:javascript
复制
// androidx.lifecycle.SavedStateViewModelFactory
override fun  create(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):

代码语言:javascript
复制
ComponentActivity.onSaveInstanceState()
  → SavedStateRegistry.performSave(outBundle)
    → 遍历所有 SavedStateProvider
      → SavedStateHandle.savedStateProvider.saveState()
        → 把 regular 中的数据打包成 Bundle
          → 存入 outBundle["androidx.lifecycle.BundlableSavedStateRegistry.key"]

恢复阶段(Activity.onCreate):

代码语言:javascript
复制
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

典型的混合使用场景

代码语言:javascript
复制
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 时

代码语言:javascript
复制
// androidx.activity.ComponentActivity
override fun onDestroy() {
    super.onDestroy()
    if (!isChangingConfigurations) {
        // 只有真正销毁时才清理 ViewModelStore
        viewModelStore?.clear()
    }
}

2. Fragment 真正移除时

代码语言:javascript
复制
// androidx.fragment.app.FragmentManager
fun performDestroy(f: Fragment) {
    if (f.mViewModelStore != null) {
        f.mViewModelStore.clear()
    }
}

3. Navigation 返回时

当你用 `NavController.popBackStack()` 离开一个 Fragment 时,它的 ViewModel 会被清理,除非你使用了 `by navGraphViewModels()` 共享作用域。

---

实战建议

1. 合理选择状态存储方式

代码语言:javascript
复制
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 中存大对象

代码语言:javascript
复制
// ❌ Bitmap 不能序列化,且太大
handle["avatar"] = bitmap

// ✅ 只存 URI,用时再加载 handle["avatar_uri"] = uri.toString()

3. 用 AbstractSavedStateViewModelFactory 支持自定义依赖

如果你的 ViewModel 既需要 SavedStateHandle,又需要其他依赖(如 Repository),可以自定义 Factory:

代码语言:javascript
复制
class MyViewModelFactory(
    private val repository: UserRepository,
    owner: SavedStateRegistryOwner,
    defaultArgs: Bundle?
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {

override fun create( key: String, modelClass: Class, handle: SavedStateHandle ): T { return MyViewModel(repository, handle) as T } }

4. 测试 ViewModel 的 SavedState 恢复逻辑

代码语言:javascript
复制
@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 页面状态管理既灵活又可靠。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • ViewModel 的生命周期为什么比 Activity 长?
    • ViewModelStore:ViewModel 的容器
    • ComponentActivity 如何持有 ViewModelStore
  • ViewModel 如何被创建?ViewModelProvider 的工厂机制
    • ViewModelProvider 的核心逻辑
    • Factory 的默认实现
  • SavedState 机制如何与 ViewModel 集成?
    • SavedStateRegistry:状态存储的核心
    • SavedStateHandle 的工作原理
    • SavedStateViewModelFactory 的创建逻辑
    • 完整的保存与恢复流程
  • 为什么配置变更和进程重建的恢复机制不同?
    • 典型的混合使用场景
  • ViewModel 什么时候真正销毁?onCleared() 的调用时机
    • 1. Activity finish 时
    • 2. Fragment 真正移除时
    • 3. Navigation 返回时
  • 实战建议
    • 1. 合理选择状态存储方式
    • 2. 不要在 SavedStateHandle 中存大对象
    • 3. 用 AbstractSavedStateViewModelFactory 支持自定义依赖
    • 4. 测试 ViewModel 的 SavedState 恢复逻辑
  • 总结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档