开局三连.....
ViewModel是什么????
ViewModel怎么用????
ViewModel怎么实现???
思考....
输入--->头发----掉掉掉--->输出....
1.ViewModel 是什么
ViewModel是一种被设计为通过能感知生命周期的方式来存储和管理 UI 相关的数据的容器类。它让数据能存活过配置变更(如屏幕旋转)而不被杀死。
核心类:
-
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 原理分析(掉头发开始)
ViewModel 是一个能感知生命周期的容器
带着问题看源码,生命感知,和容器(存储了什么)
####核心类
-
ViewModelProviderViewModel的创建类 -
ViewModelStoreViewModel的存储类 -
ViewModelViewModel对象 -
ViewModelImplViewModel的实现类
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
流程梳理:
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
ViewModelProvider.create(this)创建了ViewModelProvider和ViewModelStore对象
4:ViewModelProvider.create(this).get(xxx::class.java) 执行get(xxx::class.java) 方法
创建了ViewModel对象 并且将此对象添加到了Activity的ViewModelStore中
总结
核心类:
ViewModelProvider创建对象ViewModelStore存储对象ViewModel对象ViewModelImpl具体功能实现
ViewModel是一个有生命感知能力的容器,生命周期感知能力是基于Activity的Lifecycle生命周期,容器存储的是ViewModelStore存储的是ViewModel对象.