ViewModel 是 Android Jetpack 架构组件的核心,它不仅能在配置变更(如屏幕旋转)时保留数据,还能与 SavedState 机制配合,在进程重建后恢复状态。本文从源码层面拆解 ViewModel 的存储、恢复、与 SavedState 的集成机制,帮助你真正理解它的工作原理。
---
ViewModel 实例并不直接存储在 Activity 或 Fragment 中,而是放在一个叫 `ViewModelStore` 的容器里。这个容器本质上是一个 `HashMap<String, ViewModel>`:
// 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` 实现了 `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:
val viewModel: MyViewModel by viewModels()
// 或
val viewModel = ViewModelProvider(this)[MyViewModel::class.java]// 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,`ComponentActivity` 会提供默认的 `SavedStateViewModelFactory`:
// androidx.activity.ComponentActivity
override fun getDefaultViewModelProviderFactory(): ViewModelProvider.Factory {
return SavedStateViewModelFactory(
application,
this,
intent?.extras
)
}这个 Factory 做了两件事: 1. 支持无参构造的 ViewModel 2. 支持带 `SavedStateHandle` 参数的 ViewModel
---
`ComponentActivity` 实现了 `SavedStateRegistryOwner` 接口,它内部持有一个 `SavedStateRegistry`:
// 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` 是一个可观察的数据容器,它的数据来自 `SavedStateRegistry`:
// 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 中 } }
// 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):
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 的内部 MapViewModelProvider.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()` 会在以下情况被调用:
// androidx.activity.ComponentActivity
override fun onDestroy() {
super.onDestroy()
if (!isChangingConfigurations) {
// 只有真正销毁时才清理 ViewModelStore
viewModelStore?.clear()
}
}// androidx.fragment.app.FragmentManager
fun performDestroy(f: Fragment) {
if (f.mViewModelStore != null) {
f.mViewModelStore.clear()
}
}当你用 `NavController.popBackStack()` 离开一个 Fragment 时,它的 ViewModel 会被清理,除非你使用了 `by navGraphViewModels()` 共享作用域。
---
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 }
// ❌ Bitmap 不能序列化,且太大
handle["avatar"] = bitmap// ✅ 只存 URI,用时再加载 handle["avatar_uri"] = uri.toString()
如果你的 ViewModel 既需要 SavedStateHandle,又需要其他依赖(如 Repository),可以自定义 Factory:
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 } }
@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) }
---
理解这些机制,你就能准确判断:
ViewModel + SavedState 的组合,让 Android 页面状态管理既灵活又可靠。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。