Kotlin 之 ViewModel源码分析

332 阅读12分钟

viewmodel-lifecycle.png

开局三连.....

ViewModel是什么????

ViewModel怎么用????

ViewModel怎么实现???

思考....

输入--->头发----掉掉掉--->输出....

1.ViewModel 是什么

ViewModel是一种被设计为通过能感知生命周期的方式来存储和管理 UI 相关的数据的容器类。它让数据能存活过配置变更(如屏幕旋转)而不被杀死。

ViewModel 概览-Google

ViewModel 概览

核心类:

  • ViewModelProvider ViewModel的创建类

  • ViewModelStore ViewModel的存储类

  • ViewModel ViewModel对象

  • ViewModelImpl ViewModel的实现类

个人理解:

ViewModel 是一个能感知生命周期的容器

问题来了:

1.怎么感知生命周期???

2.是什么样的容器,存储什么数据???

2.ViewModel 怎么使用

  • 创建方式<一>

    val viewModel=ViewModelProvider.create(this).get(TestViewModel::class.java)

  • 创建方式<二>

    val viewModel: TestViewModel by viewModels()

  • 创建方式<三>

val viewModel by lazy { TestViewModel()}

使用实例:

 1. ViewModel类
 class TestViewModel:ViewModel(){
     // LiveData
      val liveData = MutableLiveData<String>()
     //数据更改
     fun update(updateStr:String) {
         liveData.value="数据更改了:"+updateStr
     }
 }
 
2.创建方式

//创建方式<一>
 val viewModel=ViewModelProvider.create(this).get(TestViewModel::class.java)
 //创建方式<二>
  val viewModel: TestViewModel by viewModels()
 //创建方式<三>
 val viewModel by lazy { TestViewModel()}

3.注册监听
  viewModel.liveData.observe(this){
         print("结果:"+it)
     }
4.更新
  viewModel.update("我更新了")


3.ViewModel 原理分析(掉头发开始)

image.png ViewModel 是一个能感知生命周期的容器

带着问题看源码,生命感知,和容器(存储了什么)

####核心类

  • ViewModelProvider ViewModel的创建类

  • ViewModelStore ViewModel的存储类

  • ViewModel ViewModel对象

  • ViewModelImpl ViewModel的实现类

3.1 相关源码

分析基于AppCompatActivity.class

3.1.1 核心类源码之ViewModelStore.class源码

ViewModelStore 维护了一个HashMap 存储 ViewModel

// 定义一个公开且可被继承的 ViewModelStore 类
// 该类用于存储和管理 ViewModel 实例
public open class ViewModelStore {
    // 私有成员变量,使用可变映射来存储 ViewModel 实例
    // 键为 String 类型,用于唯一标识每个 ViewModel
    // 值为 ViewModel 类型,存储具体的 ViewModel 实例
    private val map = mutableMapOf<String, ViewModel>()
    /**
     * 将指定的 ViewModel 实例放入存储中,并关联一个唯一的键。
     * 如果该键已经存在对应的 ViewModel 实例,会先清除旧的实例。
     * 此方法的使用范围被限制在库组内。
     *
     * @param key 用于标识 ViewModel 的唯一键
     * @param viewModel 要存储的 ViewModel 实例
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public fun put(key: String, viewModel: ViewModel) {
        // 将新的 ViewModel 实例放入映射中,并获取旧的 ViewModel 实例(如果存在)
        val oldViewModel = map.put(key, viewModel)
        // 如果旧的 ViewModel 实例存在,则调用其 clear 方法进行清理
        oldViewModel?.clear()
    }
    /**
     * 根据指定的键从存储中获取对应的 ViewModel 实例。
     * 此方法的使用范围被限制在库组内。
     *
     * @param key 用于查找 ViewModel 的键
     * @return 如果找到对应的 ViewModel 实例则返回,否则返回 null
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public operator fun get(key: String): ViewModel? {
        // 从映射中获取指定键对应的 ViewModel 实例
        return map[key]
    }
    /**
     * 获取存储中所有 ViewModel 实例的键集合。
     * 此方法的使用范围被限制在库组内。
     *
     * @return 包含所有键的不可变集合
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public fun keys(): Set<String> {
        // 返回映射中所有键的副本,避免外部直接修改原映射的键集合
        return HashSet(map.keys)
    }
    /**
     * 清除存储中所有的 ViewModel 实例,并调用每个实例的 clear 方法进行资源清理。
     * 通常在相关的 Activity 或 Fragment 销毁时调用此方法。
     */
    public fun clear() {
        // 遍历映射中的所有 ViewModel 实例
        for (vm in map.values) {
            // 调用每个 ViewModel 实例的 clear 方法进行资源清理
            vm.clear()
        }
        // 清空映射,移除所有的 ViewModel 实例
        map.clear()
    }
}
3.1.2 ViewModelProvider.class源码

ViewModelProvider是 ViewModel的创建工具

package androidx.lifecycle.viewmodel.internal

// 定义一个内部对象 ViewModelProviders,提供 ViewModel 相关的辅助功能
internal object ViewModelProviders {
   // 定义一个常量,作为 ViewModel 提供者的默认键前缀
   private const val VIEW_MODEL_PROVIDER_DEFAULT_KEY: String =
       "androidx.lifecycle.ViewModelProvider.DefaultKey"

   /**
    * 根据 ViewModel 的 KClass 生成默认的键。
    *
    * @param modelClass ViewModel 的 KClass 对象
    * @return 生成的默认键
    */
   internal fun <T : ViewModel> getDefaultKey(modelClass: KClass<T>): String {
       // 确保传入的 KClass 有规范名称,若没有则抛出异常
       val canonicalName = requireNotNull(modelClass.canonicalName) {
           "Local and anonymous classes can not be ViewModels"
       }
       // 将默认键前缀和规范名称拼接成完整的默认键
       return "$VIEW_MODEL_PROVIDER_DEFAULT_KEY:$canonicalName"
   }

   // 定义一个 CreationExtras 的键,用于标识 ViewModel 的键
   internal object ViewModelKey : CreationExtras.Key<String>

   /**
    * 抛出一个不支持操作的异常,提示 `Factory.create(String, CreationExtras)` 方法未实现。
    *
    * @return 此方法不会正常返回,总是抛出异常
    */
   internal fun <VM : ViewModel> unsupportedCreateViewModel(): VM =
       throw UnsupportedOperationException(
           "`Factory.create(String, CreationExtras)` is not implemented. You may need to " +
                   "override the method and provide a custom implementation. Note that using " +
                   "`Factory.create(String)` is not supported and considered an error."
       )

   /**
    * 根据给定的 ViewModel 初始化器集合创建一个 ViewModel 工厂。
    *
    * @param initializers ViewModel 初始化器的集合
    * @return 创建好的 ViewModel 工厂
    */
   internal fun createInitializerFactory(
       initializers: Collection<ViewModelInitializer<*>>,
   ): ViewModelProvider.Factory = InitializerViewModelFactory(*initializers.toTypedArray())

   /**
    * 根据给定的多个 ViewModel 初始化器创建一个 ViewModel 工厂。
    *
    * @param initializers 多个 ViewModel 初始化器
    * @return 创建好的 ViewModel 工厂
    */
   internal fun createInitializerFactory(
       vararg initializers: ViewModelInitializer<*>,
   ): ViewModelProvider.Factory = InitializerViewModelFactory(*initializers)

   /**
    * 根据 ViewModel 存储所有者获取默认的 ViewModel 工厂。
    *
    * @param owner ViewModel 存储所有者
    * @return 默认的 ViewModel 工厂
    */
   internal fun getDefaultFactory(owner: ViewModelStoreOwner): ViewModelProvider.Factory =
       if (owner is HasDefaultViewModelProviderFactory) {
           // 如果所有者实现了 HasDefaultViewModelProviderFactory 接口,使用其默认工厂
           owner.defaultViewModelProviderFactory
       } else {
           // 否则使用默认的工厂
           DefaultViewModelProviderFactory
       }

   /**
    * 根据 ViewModel 存储所有者获取默认的创建额外信息。
    *
    * @param owner ViewModel 存储所有者
    * @return 默认的创建额外信息
    */
   internal fun getDefaultCreationExtras(owner: ViewModelStoreOwner): CreationExtras =
       if (owner is HasDefaultViewModelProviderFactory) {
           // 如果所有者实现了 HasDefaultViewModelProviderFactory 接口,使用其默认创建额外信息
           owner.defaultViewModelCreationExtras
       } else {
           // 否则使用空的创建额外信息
           CreationExtras.Empty
       }

   /**
    * 根据给定的 ViewModel 类、创建额外信息和多个 ViewModel 初始化器创建 ViewModel 实例。
    *
    * @param modelClass ViewModel 的 KClass 对象
    * @param extras 创建额外信息
    * @param initializers 多个 ViewModel 初始化器
    * @return 创建好的 ViewModel 实例
    */
   internal fun <VM : ViewModel> createViewModelFromInitializers(
       modelClass: KClass<VM>,
       extras: CreationExtras,
       vararg initializers: ViewModelInitializer<*>,
   ): VM {
       @Suppress("UNCHECKED_CAST")
       // 从初始化器中找到第一个匹配指定 ViewModel 类的初始化器,并调用其初始化方法
       val viewModel = initializers.firstOrNull { it.clazz == modelClass }
          ?.initializer
          ?.invoke(extras) as VM?
       // 确保成功创建了 ViewModel 实例,若未创建则抛出异常
       return requireNotNull(viewModel) {
           "No initializer set for given class ${modelClass.canonicalName}"
       }
   }
}

/**
* Multiplatform replacement for [KClass.qualifiedName] reflection API.
* It's required because it's not supported for all platforms.
*/
internal expect val <T : Any> KClass<T>.canonicalName: String?
3.1.3 ViewModel.class源码

ViewModel源码 维护了一个ViewModelImpl对象

@file:JvmName("ViewModel")
@file:OptIn(ExperimentalStdlibApi::class)

package androidx.lifecycle

// 定义抽象的 ViewModel 类,用于存储和管理 UI 相关数据,在配置变更时数据可保留
public actual abstract class ViewModel {
   // 内部实现的 ViewModel 实例引用,可能为 null
   private val impl: ViewModelImpl?

   // 默认构造函数,初始化 ViewModelImpl 实例
   public actual constructor() {
       impl = ViewModelImpl()
   }

   // 带协程作用域的构造函数,使用传入的协程作用域初始化 ViewModelImpl 实例
   public actual constructor(viewModelScope: CoroutineScope) {
       impl = ViewModelImpl(viewModelScope)
   }

   // 带可变参数(一组 AutoCloseable 对象)的构造函数,使用这些对象初始化 ViewModelImpl 实例
   public actual constructor(vararg closeables: AutoCloseable) {
       impl = ViewModelImpl(*closeables)
   }

   // 既带协程作用域又带可变参数(一组 AutoCloseable 对象)的构造函数
   public actual constructor(viewModelScope: CoroutineScope, vararg closeables: AutoCloseable) {
       impl = ViewModelImpl(viewModelScope, *closeables)
   }

   // 已弃用的构造函数,使用一组 Closeable 对象初始化 ViewModelImpl 实例
   @Deprecated(message = "Replaced by `AutoCloseable` overload.", level = DeprecationLevel.HIDDEN)
   public constructor(vararg closeables: Closeable) {
       impl = ViewModelImpl(*closeables)
   }

   // 可被子类重写的方法,在 ViewModel 被清理时调用
   protected actual open fun onCleared() {}

   // 主线程调用的方法,用于清理 ViewModel,先调用 impl 的 clear 方法,再调用 onCleared 方法
   @MainThread
   internal actual fun clear() {
       impl?.clear()
       onCleared()
   }

   // 添加一个带键的 AutoCloseable 对象到 ViewModelImpl 中
   public actual fun addCloseable(key: String, closeable: AutoCloseable) {
       impl?.addCloseable(key, closeable)
   }

   // 添加一个 AutoCloseable 对象到 ViewModelImpl 中,方法可被子类重写
   public actual open fun addCloseable(closeable: AutoCloseable) {
       impl?.addCloseable(closeable)
   }

   // 已弃用的方法,添加一个 Closeable 对象到 ViewModelImpl 中
   @Deprecated(message = "Replaced by `AutoCloseable` overload.", level = DeprecationLevel.HIDDEN)
   public open fun addCloseable(closeable: Closeable) {
       impl?.addCloseable(closeable)
   }

   // 根据键从 ViewModelImpl 中获取 AutoCloseable 对象
   public actual fun <T : AutoCloseable> getCloseable(key: String): T? = impl?.getCloseable(key)
}
3.1.4 ViewModelImpl.class源码

ViewModel的功能实现

@file:OptIn(ExperimentalStdlibApi::class)
package androidx.lifecycle.viewmodel.internal

// ViewModel 的内部实现类,用于管理 ViewModel 相关资源
internal class ViewModelImpl {
   // 用于线程同步的锁对象,保证对资源的并发访问安全
   private val lock = Any()
   // 存储带键的 AutoCloseable 资源的映射,键为 String 类型,值为 AutoCloseable 类型
   private val keyToCloseables = mutableMapOf<String, AutoCloseable>()
   // 存储无键的 AutoCloseable 资源的集合
   private val closeables = mutableSetOf<AutoCloseable>()
   // 标记 ViewModel 是否已经被清理,使用 Volatile 保证多线程可见性
   @Volatile
   private var isCleared = false

   // 默认构造函数
   constructor()

   // 带协程作用域的构造函数,将协程作用域作为可关闭资源添加
   constructor(viewModelScope: CoroutineScope) {
       addCloseable(VIEW_MODEL_SCOPE_KEY, viewModelScope.asCloseable())
   }

   // 带一组 AutoCloseable 资源的构造函数,将这些资源添加到无键集合中
   constructor(vararg closeables: AutoCloseable) {
       this.closeables += closeables
   }

   // 既带协程作用域又带一组 AutoCloseable 资源的构造函数
   constructor(viewModelScope: CoroutineScope, vararg closeables: AutoCloseable) {
       addCloseable(VIEW_MODEL_SCOPE_KEY, viewModelScope.asCloseable())
       this.closeables += closeables
   }

   // 清理 ViewModel 相关资源的方法,在主线程调用
   @MainThread
   fun clear() {
       // 如果已经清理过,直接返回
       if (isCleared) return
       // 标记为已清理
       isCleared = true
       // 加锁保证资源清理操作的线程安全
       synchronized(lock) {
           // 关闭带键的资源
           for (closeable in keyToCloseables.values) {
               closeWithRuntimeException(closeable)
           }
           // 关闭无键的资源
           for (closeable in closeables) {
               closeWithRuntimeException(closeable)
           }
           // 清空无键资源集合,避免意外重新创建资源
           closeables.clear()
       }
   }

   // 添加带键的 AutoCloseable 资源的方法
   fun addCloseable(key: String, closeable: AutoCloseable) {
       // 如果已经清理,直接关闭该资源
       if (isCleared) {
           closeWithRuntimeException(closeable)
           return
       }
       // 加锁保证操作的线程安全
       synchronized(lock) {
           // 获取旧的资源
           val oldCloseable = keyToCloseables.put(key, closeable)
           // 关闭旧的资源
           closeWithRuntimeException(oldCloseable)
       }
   }

   // 添加无键的 AutoCloseable 资源的方法
   fun addCloseable(closeable: AutoCloseable) {
       // 如果已经清理,直接关闭该资源
       if (isCleared) {
           closeWithRuntimeException(closeable)
           return
       }
       // 加锁保证操作的线程安全
       synchronized(lock) {
           // 将资源添加到无键集合中
           closeables += closeable
       }
   }

   // 根据键获取 AutoCloseable 资源的方法
   fun <T : AutoCloseable> getCloseable(key: String): T? {
       // 加锁保证操作的线程安全
       synchronized(lock) {
           // 从映射中获取资源并进行类型转换
           return keyToCloseables[key] as T?
       }
   }

   // 关闭 AutoCloseable 资源的方法,将异常封装为 RuntimeException 抛出
   private fun closeWithRuntimeException(closeable: AutoCloseable?) {
       try {
           closeable?.close()
       } catch (e: Exception) {
           throw RuntimeException(e)
       }
   }
}
3.1.5 ComponentActivity.class 中ViewModel的相关代码

ComponentActivity实现了 ViewModelStoreOwner接口 创建了ViewModelStore对象 注册了页面销毁后ViewModelStore的清理操作

@file:OptIn(ExperimentalStdlibApi::class)
package androidx.activity

// 定义 ComponentActivity 类,它继承自 androidx.core.app.ComponentActivity,
// 并实现了 ViewModelStoreOwner 和 HasDefaultViewModelProviderFactory 接口,
// 用于管理 ViewModel 相关的功能,支持在 Activity 中使用 ViewModel
open class ComponentActivity() : androidx.core.app.ComponentActivity(),
   ViewModelStoreOwner,
   HasDefaultViewModelProviderFactory {

   // 内部类,用于存储非配置更改时需要保留的实例,包含自定义对象和 ViewModelStore
   internal class NonConfigurationInstances {
       var custom: Any? = null
       var viewModelStore: ViewModelStore? = null
   }

   // 用于存储 ViewModel 的引用,初始为 null,会在需要时进行初始化
   private var _viewModelStore: ViewModelStore? = null

   // 初始化块,在类实例创建时执行,主要进行一些初始化操作
   init {
       // 监听 Lifecycle 的 ON_DESTROY 事件,当 Activity 销毁且不是因为配置更改时,清除 ViewModelStore
       lifecycle.addObserver(LifecycleEventObserver { _, event ->
           if (event == Lifecycle.Event.ON_DESTROY) {
               if (!isChangingConfigurations) {
                   viewModelStore.clear()
               }
           }
       })
       // 监听 Lifecycle 状态变化,确保在合适的时候初始化 ViewModelStore
       lifecycle.addObserver(object : LifecycleEventObserver {
           override fun onStateChanged(
               source: LifecycleOwner,
               event: Lifecycle.Event
           ) {
               ensureViewModelStore()
               lifecycle.removeObserver(this)
           }
       })
       // 启用 SavedStateHandle 功能,用于保存和恢复 ViewModel 的状态
       enableSavedStateHandles()
   }

   // 重写 ViewModelStoreOwner 接口的方法,获取与当前 Activity 关联的 ViewModelStore
   override val viewModelStore: ViewModelStore
       get() {
           // 检查 Activity 是否已经附加到 Application 实例,若未附加则抛出异常
           checkNotNull(application) {
               ("Your activity is not yet attached to the " +
                       "Application instance. You can't request ViewModel before onCreate call.")
           }
           // 确保 ViewModelStore 已经初始化
           ensureViewModelStore()
           return _viewModelStore!!
       }

   // 确保 ViewModelStore 已经初始化,如果未初始化则尝试从 NonConfigurationInstances 中恢复,若仍未获取到则创建新的 ViewModelStore
   private fun ensureViewModelStore() {
       if (_viewModelStore == null) {
           val nc = lastNonConfigurationInstance as NonConfigurationInstances?
           if (nc != null) {
               _viewModelStore = nc.viewModelStore
           }
           if (_viewModelStore == null) {
               _viewModelStore = ViewModelStore()
           }
       }
   }

   // 重写 HasDefaultViewModelProviderFactory 接口的方法,通过懒加载的方式创建默认的 ViewModel 工厂
   override val defaultViewModelProviderFactory: ViewModelProvider.Factory by lazy {
       SavedStateViewModelFactory(
           application,
           this,
           if (intent != null) intent.extras else null
       )
   }

   // 重写 HasDefaultViewModelProviderFactory 接口的方法,获取默认的 ViewModel 创建额外信息
   override val defaultViewModelCreationExtras: CreationExtras
       get() {
           // 创建可变的额外信息对象
           val extras = MutableCreationExtras()
           if (application != null) {
               // 将 Application 实例添加到额外信息中
               extras[APPLICATION_KEY] = application
           }
           // 将当前 Activity 作为 SavedStateRegistryOwner 添加到额外信息中
           extras[SAVED_STATE_REGISTRY_OWNER_KEY] = this
           // 将当前 Activity 作为 ViewModelStoreOwner 添加到额外信息中
           extras[VIEW_MODEL_STORE_OWNER_KEY] = this
           val intentExtras = intent?.extras
           if (intentExtras != null) {
               // 将 Intent 的额外信息添加到额外信息中
               extras[DEFAULT_ARGS_KEY] = intentExtras
           }
           return extras
       }

   // 重写 onRetainNonConfigurationInstance 方法,在 Activity 进行非配置更改时保留必要的实例信息
   @Suppress("deprecation")
   final override fun onRetainNonConfigurationInstance(): Any? {
       // 获取自定义的非配置实例
       val custom = onRetainCustomNonConfigurationInstance()
       var viewModelStore = _viewModelStore
       if (viewModelStore == null) {
           // 若当前 ViewModelStore 为空,尝试从之前的 NonConfigurationInstances 中获取
           val nc = lastNonConfigurationInstance as NonConfigurationInstances?
           if (nc != null) {
               viewModelStore = nc.viewModelStore
           }
       }
       if (viewModelStore == null && custom == null) {
           return null
       }
       // 创建新的 NonConfigurationInstances 对象并存储相关信息
       val nci = NonConfigurationInstances()
       nci.custom = custom
       nci.viewModelStore = viewModelStore
       return nci
   }

   // 用于保留自定义的非配置实例,已弃用,建议使用 ViewModel 来存储非配置状态
   @Deprecated("Use a {@link androidx.lifecycle.ViewModel} to store non config state.")
   open fun onRetainCustomNonConfigurationInstance(): Any? {
       return null
   }

   // 获取之前保留的自定义非配置实例,已弃用,建议使用 ViewModel 来存储非配置状态
   @get:Deprecated("Use a {@link androidx.lifecycle.ViewModel} to store non config state.")
   open val lastCustomNonConfigurationInstance: Any?
       get() {
           val nc = lastNonConfigurationInstance as NonConfigurationInstances?
           return nc?.custom
       }

   // 重写 setContentView 方法,设置内容视图,同时初始化视图树的 ViewModelStoreOwner
   override fun setContentView(view: View?) {
       initializeViewTreeOwners()
       super.setContentView(view)
   }

   // 重写 setContentView 方法,设置内容视图及布局参数,同时初始化视图树的 ViewModelStoreOwner
   override fun setContentView(view: View?, params: ViewGroup.LayoutParams?) {
       initializeViewTreeOwners()
       super.setContentView(view, params)
   }

   // 重写 addContentView 方法,添加内容视图及布局参数,同时初始化视图树的 ViewModelStoreOwner
   override fun addContentView(
       view: View?,
       params: ViewGroup.LayoutParams?
   ) {
       initializeViewTreeOwners()
       super.addContentView(view, params)
   }

   // 初始化视图树的 ViewModelStoreOwner,确保视图树中的组件可以访问 ViewModelStore
   open fun initializeViewTreeOwners() {
       window.decorView.setViewTreeViewModelStoreOwner(this)
   }
}
3.2 ViewModel 的调用逻辑

前提了解:

  • ComponentActivity实现了ViewModelStoreOwner接口
  • 提供了viewModelStore 对象和ViewModelStore 的get方法
  • 在init[]代码块中初始化了生命周期的监听,销毁的时候清空 viewModelStore

image.png 流程梳理:

1:ComponentActivity实现了ViewModelStoreOwner接口,在init{}中注册了生命周期回调处理ViewModelStore的清空操作,提供了ViewModelStore的get方法

2:ViewModelProvider.create(this).get(xxx::class.java)创建ViewModelProvider,ViewModel

3:ViewModelProvider.create(this)ComponentActivity实现了ViewModelStoreOwner接口所以this 是ViewModelStoreOwner

image.png ViewModelProvider.create(this)创建了ViewModelProvider和ViewModelStore对象

4:ViewModelProvider.create(this).get(xxx::class.java) 执行get(xxx::class.java) 方法

创建了ViewModel对象 并且将此对象添加到了Activity的ViewModelStore中

image.png

总结

核心类:

  • ViewModelProvider 创建对象
  • ViewModelStore 存储对象
  • ViewModel对象
  • ViewModelImpl具体功能实现

ViewModel是一个有生命感知能力的容器,生命周期感知能力是基于Activity的Lifecycle生命周期,容器存储的是ViewModelStore存储的是ViewModel对象.

image.png

image.png