Jetpack ViewModel源码分析

概述

ViewModel 是一种可以感知生命周期的来存储和管理的与 UI 相关的数据。能在屏幕旋转、预言切换等配置变更时保存数据,避免数据丢失和重复加载。

核心类

  • ViewModel:抽象类

    • 用于管理与UI相关的数据。
  • ViewModelStore:类

    • 用于存储 ViewModel 的容器。
    • 内部是 HashMap <String, ViewModel> 的数据结构,键是 ViewModel 的类名,值是 ViewModel 实例。
    • 每个 Activity/Fragment 内部都持有一个 ViewModelStore 实例。
  • ViewModelStoreOwner:接口

    • Activity/Fragment 是其实现类。
    • 用于定义获取 ViewModelStore 的规范,指明 ViewModel 的作用域,是和哪个 Activity/Fragment 绑定。
  • ViewModelProvider:类

    • 用于获取 ViewModel 实例。
    • 会检查 ViewModelStore 是否缓存,如果有缓存则直接返回实例,如果没有缓存则通过 Factory 创建新实例,并存入 ViewModelStore。
  • ViewModel:数据管理类。

  • ViewModelProvider:用于创建管理ViewModel实例。

  • ViewModelStore:用于存储ViewModel实例。

  • ViewModelStoreOwner:是一个接口,用于获取ViewModelStore实例。

  • Activity$NonConfigurationInstances:用于配置变更情况下缓存数据。

生命周期图

在这里插入图片描述

流程

  • 获取 ViewModel:首次调用 ViewModelProvider(this).get(MyViewModel::class.java) 时,ViewModeProvider 会尝试从 Activity 的 ViewModelStore 中获取 ViewModel 实例。
  • 创建和存储 ViewModel:如果 ViewModelStore 中没有该实例,则通过 ViewModelProvider 创建实例;如果存在实例,则直接返回。
  • 配置发生变更:当屏幕旋转时,系统会先销毁再重建 Activity,
    • 被销毁前,会调用 onRetainNonConfigurationInstance() ,系统会缓存 Activity 的ViewModelStore 对象。
    • 重建后,新 Activity 被创建, ViewModelProvider 通过保留下来的 ViewModelStore 获取 ViewModel 实例。

源码分析

创建阶段

ViewModelProvider类基本属性
public open class ViewModelProvider @JvmOverloads constructor(
    private val store: ViewModelStore,
    private val factory: Factory,
    private val defaultCreationExtras: CreationExtras = CreationExtras.Empty,
) {
    public constructor(
        owner: ViewModelStoreOwner
    ) : this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))

    public constructor(owner: ViewModelStoreOwner, factory: Factory) : this(
        owner.viewModelStore,
        factory,
        defaultCreationExtras(owner)
    )

    public interface Factory {
        public fun <T : ViewModel> create(modelClass: Class<T>): T {
            throw UnsupportedOperationException(
                "Factory.create(String) is unsupported.  This Factory requires " +
                "`CreationExtras` to be passed into `create` method."
            )
        }
    }
}
ViewModelProvider#get()
public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
    // 获取ViewModel类的完整类名
    val canonicalName = modelClass.canonicalName
        ?: throw IllegalArgumentException("Local and anonymous classes can not be ViewModels")
    // 使用类名作为key值
    return get("$DEFAULT_KEY:$canonicalName", modelClass)
}
@MainThread
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
    // 先从ViewModelStore中获取ViewModel实例
    val viewModel = store[key]
    if (modelClass.isInstance(viewModel)) {
        // 如果ViewModel实例存在,则直接返回
        (factory as? OnRequeryFactory)?.onRequery(viewModel!!)
        return viewModel as T
    } else {
      	// ViewModel实例的类型不匹配
        if (viewModel != null) {
            // TODO: log a warning.
        }
    }
    val extras = MutableCreationExtras(defaultCreationExtras)
    extras[VIEW_MODEL_KEY] = key
         
    // 通过Factory创建ViewModel实例
    return try {
        factory.create(modelClass, extras)
    } catch (e: AbstractMethodError) {
        factory.create(modelClass)
    }.also { 
        // 将新创建的ViewModel实例存入ViewModelStore中
        store.put(key, it) 
    }
}

保存阶段

ComponentActivity#onRetainNonConfigurationInstance()
// 配置变更时会销毁Activity,销毁前会回调该方法
final override fun onRetainNonConfigurationInstance(): Any? {
    // Maintain backward compatibility.
    val custom = onRetainCustomNonConfigurationInstance()
    // 获取当前的ViewModelStore
    var viewModelStore = _viewModelStore
    if (viewModelStore == null) {
        val nc = lastNonConfigurationInstance as NonConfigurationInstances?
        if (nc != null) {
            viewModelStore = nc.viewModelStore
        }
    }
    if (viewModelStore == null && custom == null) {
        return null
    }
    // 通过NonConfigurationInstances实例缓存ViewModelStore对象
    val nci = NonConfigurationInstances()
    nci.custom = custom
    nci.viewModelStore = viewModelStore
    // 返回系统对象
    return nci
}

恢复阶段

Activiy 被重建了,调用 ViewModelProvider(this) 创建新的 ViewModelProvider 实例,会调用 ComponentActivity 的 viewModelStore 访问器。

ComponentActivity.viewModelStore属性
override val viewModelStore: ViewModelStore
    get() {
        checkNotNull(application) {
            ("Your activity is not yet attached to the " +
                "Application instance. You can't request ViewModel before onCreate call.")
        }
        ensureViewModelStore()
        return _viewModelStore!!
    }
ComponentActivity#ensureViewModelStore()
private fun ensureViewModelStore() {
    if (_viewModelStore == null) {
        val nc = lastNonConfigurationInstance as NonConfigurationInstances?
        // 如果配置对象存在,则获取ViewModelStore实例
        if (nc != null) {
             _viewModelStore = nc.viewModelStore
        }
        // 如果配置对象不存在,则创建ViewModelStore实例
        if (_viewModelStore == null) {
            _viewModelStore = ViewModelStore()
        }
    }
}

总结

  • 创建ViewModel阶段:通过 by viewModels() 创建 ViewModel 实例,本质是调用 ViewModelProvider(this).get(MyViewModel::class.java),会先尝试从 ViewModelStore 中获取,ViewModelStore 是一个哈希表的数据结构,如果没有则新建并缓存在 ViewModelStore,ViewModelStore 是ComponentActivity中的一个属性。
  • 缓存ViewModel阶段:在配置变更情况下,ViewModelStore 会被缓存在 NonconfigurationInstances 中。
  • 恢复ViewModel阶段:配置变更后会重启 Activity,会先从 NonconfigurationInstances 中读取 ViewModelStore,接着获取 ViewModel 实例。
  • Activity 正常销毁时会清空 ViewModelStore。
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐