故城县网站建设服务商业网站开发
web/
2025/10/8 13:58:39/
文章来源:
故城县网站建设服务,商业网站开发,制作网站南京,线上投票怎么弄Android Jetpack组件架构#xff1a;ViewModel的原理 导言
本篇文章是关于介绍ViewModel的#xff0c;由于ViewModel的使用还是挺简单的#xff0c;这里就不再介绍其的基本应用#xff0c;我们主要来分析ViewModel的原理。
ViewModel的生命周期
众所周知#xff0c;一般…Android Jetpack组件架构ViewModel的原理 导言
本篇文章是关于介绍ViewModel的由于ViewModel的使用还是挺简单的这里就不再介绍其的基本应用我们主要来分析ViewModel的原理。
ViewModel的生命周期
众所周知一般使用ViewModel是用来解决两个问题的第一个就是关于设备配置发生改变时Activity先前状态的保存在ViewModel出来之前我们一般会使用saveInstanceState这个Bundle来进行状态的保存但是这样做能存储的数据是有限的结构也不够明确ViewModel作为一个生命周期大于Activity的组件就可以帮我们实现状态的存储下面是ViewModel生命周期与Activity对比的图 可以看到直到Activity被完全Destory时ViewModel中的数据才会被清除。
我们使用ViewModel的第二个原因就是用来实现MVVM架构可以通过DataBinding组件和ViewModel组件以及LiveData组件一起实现MVVM架构这样可以减轻Activity的职责避免Activity过于臃肿。
获得ViewModel的提供者
我们从ViewModel的创建开始分析其原理这里用我们上一篇文章的例子
mViewModel ViewModelProvider(this).get(SimpViewModel::class.java)这里首先会通过ViewModelProvider的构造方法获得一个ViewModelProvider的实例其构造方法如下所示
public constructor(owner: ViewModelStoreOwner
) : this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))constructor(private val store: ViewModelStore,private val factory: Factory,private val defaultCreationExtras: CreationExtras CreationExtras.Empty,
)可以看到我们调用的是第一个构造方法最终会调用到第二个构造方法中也就是主构造方法中这个构造来说就是指定了三个成员变量分别是ViewModelStore,Factory和CreationExtras三个类型的参数我们先来分别介绍一下这三个类型。
ViewModelStore – ViewModel的拥有者
着整个类比较小但是也是有注释的我们先来看看注释 这段注释中比较重要的信息就是ViewModel是真正用来存储ViewModel的类并且在configuration changes就是配置发生改变时新的实例和旧的实例中的信息是一致的。只有当持有者不再会被recreated时里面的数据才会通过clear清除。
接下来我们来看该类的源码
public class ViewModelStore {private final HashMapString, ViewModel mMap new HashMap();final void put(String key, ViewModel viewModel) {ViewModel oldViewModel mMap.put(key, viewModel);if (oldViewModel ! null) {oldViewModel.onCleared();}}final ViewModel get(String key) {return mMap.get(key);}SetString keys() {return new HashSet(mMap.keySet());}public final void clear() {for (ViewModel vm : mMap.values()) {vm.clear();}mMap.clear();}
}可以看到具体是用一个哈希表来存储viewModel的实例的里面唯一比较大的方法就是put方法里面做的处理就是将替换出来的旧的viewModel实例给清理掉。
Factory – ViewModel的创建工厂
这个Factory是一个定义在ViewModelProvider的内部接口它的主要职责是用来初始化ViewModel说实话就是一个工厂。我们来看其定义 public interface Factory {public fun T : ViewModel create(modelClass: ClassT): T {throw UnsupportedOperationException(Factory.create(String) is unsupported. This Factory requires CreationExtras to be passed into create method.)}public fun T : ViewModel create(modelClass: ClassT, extras: CreationExtras): T create(modelClass)companion object {JvmStaticfun from(vararg initializers: ViewModelInitializer*): Factory InitializerViewModelFactory(*initializers)}}不过这里是一个抽象的我们来找一个具体的也就是defaultFactory方法获取的工厂
public companion object {internal fun defaultFactory(owner: ViewModelStoreOwner): Factory if (owner is HasDefaultViewModelProviderFactory)owner.defaultViewModelProviderFactory else instance......
}这个方法的逻辑就是判断ViewModel的持有者是不是有默认的工厂方法如果有的话就获取持有者的默认工厂否则返回的是自身的instance实例至于这个instance实例是在NewInstanceFactory这个实现了Factory接口的工厂类中定义的伴生变量具体逻辑是
JvmStatic
public val instance: NewInstanceFactoryRestrictTo(RestrictTo.Scope.LIBRARY_GROUP)get() {if (sInstance null) {sInstance NewInstanceFactory()}return sInstance!!}可以看到instance是一个静态的单例他具体指向的还是这个NewInstanceFactory类至于它是如何初始化/创建ViewModel的实例的我们可以看一眼它的create方法
override fun T : ViewModel create(modelClass: ClassT): T {return try {modelClass.newInstance()} catch (e: InstantiationException) {throw RuntimeException(Cannot create an instance of $modelClass, e)} catch (e: IllegalAccessException) {throw RuntimeException(Cannot create an instance of $modelClass, e)}
}这个传入的modelClass就是我们传入的.class文件
ViewModelProvider(this).get(SimpViewModel::class.java)所以可以看到这个默认情况下的工厂就是直接用反射生成了对应ViewModel的实例。
CreationExtras – 构建ViewModel时的额外参数
首先我们来看一看注释的内容 简单来说它就是为工厂生成实例的时候提供额外参数的这些参数使用一个Map来存储的了不过默认情况下我们并不需要实现额外的工厂所以这个类型我们先略过。
获得ViewModel的实例
前面我们已经知道了通过构造ViewModelProvider我们可以获得其Factory了接下来继续向下看
ViewModelProvider(this).get(SimpViewModel::class.java)我们看一看get方法做了什么 public open operator fun T : ViewModel get(modelClass: ClassT): T {val canonicalName modelClass.canonicalName?: throw IllegalArgumentException(Local and anonymous classes can not be ViewModels)return get($DEFAULT_KEY:$canonicalName, modelClass)}public open operator fun T : ViewModel get(key: String, modelClass: ClassT): T {val viewModel store[key]if (modelClass.isInstance(viewModel)) {(factory as? OnRequeryFactory)?.onRequery(viewModel)return viewModel as T} else {Suppress(ControlFlowWithEmptyBody)if (viewModel ! null) {// TODO: log a warning.}}val extras MutableCreationExtras(defaultCreationExtras)extras[VIEW_MODEL_KEY] keyreturn try {factory.create(modelClass, extras)} catch (e: AbstractMethodError) {factory.create(modelClass)}.also { store.put(key, it) }}可以看到第一个方法会调用第二个方法其中第一个方法向第二个方法传入的的第一个String类型的参数是通过DEFAULT_KEY和我们传入的类的类名拼接而成的。然后跳转到第二个方法之中去首先会尝试从ViewModleStroe中获取对应Key对应的ViewModel但是一般第一次创建时应该会为null所以之后跳转的应该是最后return块中的factory.create方法之中这个方法我们在之前Factory的介绍中提到过了具体就是通过反射实例化ViewModel的并且最后将其放入到ViewModelStore对象之中去。
至于多次获取同一个ViewModel实例是会跳转到 if (modelClass.isInstance(viewModel)) {(factory as? OnRequeryFactory)?.onRequery(viewModel)return viewModel as T} 这一段中去这里onRequery默认是无实现的也就是说并不会对viewModel做任何的处理。
ViewModelStore在哪里被创建
既然ViewModel是被存储在ViewModelStore之中的那ViewModelStore究竟是在哪里被创建出来的呢我们可以在ComponentActivity之中找到答案
public ViewModelStore getViewModelStore() {if (getApplication() null) {throw new IllegalStateException(Your activity is not yet attached to the Application instance. You cant request ViewModel before onCreate call.);}ensureViewModelStore();return mViewModelStore;
}void ensureViewModelStore() {if (mViewModelStore null) {NonConfigurationInstances nc (NonConfigurationInstances) getLastNonConfigurationInstance(); //获得上次配置更改的相关参数if (nc ! null) { //当存在上次的参数时// Restore the ViewModelStore from NonConfigurationInstancesmViewModelStore nc.viewModelStore; //恢复上次的参数}if (mViewModelStore null) {mViewModelStore new ViewModelStore(); //创建一个新的ViewModelStore}}
}可以看到这里在获得ViewModelStore时主要是通过一个NonConfigurationInstances 而该参数是一个静态的对象也就是说它是一个单例这样就保证了Activity在整个生命周期之中只有一个ViewModelStore实例从而实现配置改变时也可以恢复数据的作用。
Activity的默认工厂
在看ComponentActivity的源码时发现了原来Activity也是有默认工厂的它的具体实现如下 constructor(application: Application?, owner: SavedStateRegistryOwner, defaultArgs: Bundle?) {savedStateRegistry owner.savedStateRegistrylifecycle owner.lifecyclethis.defaultArgs defaultArgsthis.application applicationfactory if (application ! null) getInstance(application)else ViewModelProvider.AndroidViewModelFactory()}这个方法最终设置到的工厂类都是一个名为AndroidViewModelFactory的工厂类 public open class AndroidViewModelFactoryprivate constructor(private val application: Application?,// parameter to avoid clash between constructors with nullable and non-nullable// ApplicationSuppress(UNUSED_PARAMETER) unused: Int,) : NewInstanceFactory() {Suppress(SingletonConstructor)public constructor() : this(null, 0)Suppress(SingletonConstructor)public constructor(application: Application) : this(application, 0)Suppress(DocumentExceptions)override fun T : ViewModel create(modelClass: ClassT, extras: CreationExtras): T {return if (application ! null) {create(modelClass)} else {val application extras[APPLICATION_KEY]if (application ! null) {create(modelClass, application)} else {// For AndroidViewModels, CreationExtras must have an application setif (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {throw IllegalArgumentException(CreationExtras must have an application by APPLICATION_KEY)}super.create(modelClass)}}}Suppress(DocumentExceptions)override fun T : ViewModel create(modelClass: ClassT): T {return if (application null) {throw UnsupportedOperationException(AndroidViewModelFactory constructed with empty constructor works only with create(modelClass: ClassT, extras: CreationExtras).)} else {create(modelClass, application)}}Suppress(DocumentExceptions)private fun T : ViewModel create(modelClass: ClassT, app: Application): T {return if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {//如果传入的Class类型实现的接口和AndroidViewModel::class一致及说明也有生命周期调用构造犯法并且传入application对象try {modelClass.getConstructor(Application::class.java).newInstance(app)} catch (e: NoSuchMethodException) {throw RuntimeException(Cannot create an instance of $modelClass, e)} catch (e: IllegalAccessException) {throw RuntimeException(Cannot create an instance of $modelClass, e)} catch (e: InstantiationException) {throw RuntimeException(Cannot create an instance of $modelClass, e)} catch (e: InvocationTargetException) {throw RuntimeException(Cannot create an instance of $modelClass, e)}} else super.create(modelClass)}public companion object {internal fun defaultFactory(owner: ViewModelStoreOwner): Factory if (owner is HasDefaultViewModelProviderFactory)owner.defaultViewModelProviderFactory else instanceinternal const val DEFAULT_KEY androidx.lifecycle.ViewModelProvider.DefaultKeyprivate var sInstance: AndroidViewModelFactory? nullJvmStaticpublic fun getInstance(application: Application): AndroidViewModelFactory {if (sInstance null) {sInstance AndroidViewModelFactory(application)}return sInstance!!}private object ApplicationKeyImpl : KeyApplicationJvmFieldval APPLICATION_KEY: KeyApplication ApplicationKeyImpl}}具体通过getInstance方法就跳转到了这里可以发现似乎工厂类都是一个单例的模式这个工厂的特殊之处就是他的create方法涉及到了Application对象的传入比如说这里的newInstance方法
modelClass.getConstructor(Application::class.java).newInstance(app)public T newInstance(Object ... initargs)throws InstantiationException, IllegalAccessException,IllegalArgumentException, InvocationTargetException
{if (serializationClass null) {return newInstance0(initargs);} else {return (T) newInstanceFromSerialization(serializationCtor, serializationClass);}
}也就是说整个被传入Application的生命周期内都只有一个实例这样由于创建的实例在生命周期范围内的单例性和ViewModelStore的单例性整个ViewModel就可以实现在整个Activity的生命周期内(发生意外比如说配置改变时)数据不变更的作用。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/89086.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!