Android-ViewModel原理解析

 我来答
机器1718
2022-07-25 · TA获得超过6855个赞
知道小有建树答主
回答量:2805
采纳率:99%
帮助的人:162万
展开全部

在这四个方法中,其实唯一的区别就是要不要传Factory,当没有传自定义的Factory的时候,则会传入默认的Factory,我们看ViewModelProvider构造器的源码和部分of方法的源码:

在ViewModelProvider中需要传入一个VieModelStore对象,这个对象是由ViewModelStoreOwner来提供的,而在Activity或者Fragment中,是由Activity和Fragment来提供的,因为ViewModelStoreOwner是一个接口,而AppCompatActivity的祖父ComponentActivity和Fragment均实现了ViewModelStoreOwner接口。

但是ViewModelProviders在新的lifecycle-extensions库中,已经是属于被弃用的。新版的API直接使用ViewModelProvider,而不是ViewModelProviders。
比如:

可以如下的方式在baseActivity中添加,由子类Activity调用:

创建ViewModel对象,首先就需要先初始化一个ViewModelProvider对象

可以看出,ViewModelProvider构造函数其实最终都是需要两个参数,一个是ViewModelStoreOwner对象,一个是Factory。而ViewModelStoreOwner其实就是用来获取一个ViewModelStore对象来保存ViewModel对象的。而Factory就是用来创建ViewModel对象的。

这个接口的主要实现的作用就是返回一个ViewModelStore对象。在Android中,Activity和Fragment都会实现该接口,并且实现getViewModelStore()方法。
比如Activity就是在FragmentActivity的父类ComponentActivity中实现了ViewModelStoreOwner接口

Fragment的ViewModelStore其实是由FragmentManager进行管理获取

每个FragmentActivity都会有一个自己的FragmentManager对象,所以每个FragmentManagerViewModel对象,管理的是一个FragmentActivity中的所有的Fragment对应的ViewModel。具体看FragmentManagerViewModel的getViewModelStore方法

从这里可以看出,每个Fragment都会有自己的ViewModelStore对象,而ViewModelStore对象,是根据每个Fragment的唯一标识进行创建的。

ViewModelStore类对象,是每个Activity或者Fragment都有一个,目的是用于保存该页面的ViewModel对象,方便ViewModel的管理

从ViewModelProvider的get方法中,可以看出,get方法传入的是一个ViewModel.class的Class类型,然后通过这个类型,得到ViewModel的规范名称。将ViewModel对象缓存在ViewModelStore中的HashMap中。而ViewModel的创建,其实是通过ViewModelProvider.Factory来实现的

ViewModelProviders的of方法,用于返回一个ViewModelProvider对象

从这里我们可以看到,如果传入的Activity或者Fragment有getDefaultViewModelProviderFactory方法实现,而factory为null的时候,则会通过getDefaultViewModelProviderFactory创建对应的Factory,而如果没有getDefaultViewModelProviderFactory的实现,那么就会调用NewInstanceFactory来创建对应的Factory,而NewInstanceFactory其实就是创建AndroidViewModelFactory对象。
最终ViewModel对象,其实就是通过AndroidViewModelFactory的create的方法实现来创建。一般就是通过Class.newInstance或者Class.getConstructor来创建对象。

而ViewModelProvider的第一个参数,其实最终传入的是ViewModelStore对象,这个对象内部是通过一个HashMap来保存ViewModel对象
而新版的源码,ViewModelStore对象是通过Fragment和FragmentActivity对象的getViewModelStore方法来获取,而原先的HolderFragment的功能都移植到了Fragment中

HolderFragment通过设置setRetainInstance(true),使得自身能够不受到屏幕旋转等configuration
changes影响而存活,直到依附的Activity正常结束。
因为HolderFragment的生命周期,ViewModelStore对象保存在HolderFragment中,而ViewModel又存储在ViewModelStore中,这就是为什么我们说ViewModel类能够让数据在屏幕旋转等配置信息改变导致UI重建的情况下不被销毁。

ViewModelProvider的get方法:

在ViewModel中,有两种Factory,Factory是的类型是由ViewModelProvider在初始化的时候创建的,所以是由ViewModelProvider决定Factory的类型。在ViewModelProvider中,有两种Factory,一种是默认的Factory,默认的Factory是通过在ComponentActivity或者Fragment中实现HasDefaultViewModelProviderFactory接口,然后在getDefaultViewModelProviderFactory()方法中初始化一个SavedStateViewModelFactory对象;另一种Factory则是NewInstanceFactory,这种是通过NewInstanceFactory.getInstance()的单例方式获取。

其实就是通过ViewModel的Class对象,然后通过反射创建ViewModel对象,然后保存到ViewModelStore中的Map集合中
从ViewModelProvider的get方法可以看出,在ViewModelProvider的get方法中会根据Factory的类型,进行不同方法的调用。SavedStateViewModelFactory是实现了ViewModelProvider.KeyedFactory接口的,所以在创建ViewModel的时候,调用的是SavedStateViewModelFactory的create方法。

AndroidViewModel和ViewModel的构造器参数Class

ViewModel保存和恢复数据
ComponentActivity和Fragment都将数据的保存和恢复逻辑转发给了SavedStateRegistryController。在在onCreate方法里通过调用performRestore来恢复数据,在onSaveInstanceState方法里通过调用performSave来保存数据。而SavedStateRegistryController中的SavedStateRegistry对象,就是实际进行数据的保存和恢复的,在SavedStateRegistry通过唯一的key获取到一个SavedStateProvider,而SavedStateProvider其实就是返回需要保存的数据,将对应的需要缓存的数据一一返回,然后保存在系统缓存时的回调到onSaveInstanceState的方法参数Bundle中进行保存。
SavedStateRegistry.performSave()
该方法是由ComponentActivity的onSaveInstanceState方法触发调用SavedStateRegistryController的performSave,进而调用的

在SavedStateRegistry恢复数据的时候,会把恢复后的数据都交给SavedStateHandle。希望保留的数据,可以通过两种方式向mRegular保存数据。

在ComponentActivity恢复数据的时候,会通过SavedStateRegistryController.performSave在Activity的onSaveInstanceState方法中进行数据的保存,然后在ComponentActivity的onCreate方法中,通过调用SavedStateRegistryController.performRestore方法进行数据的恢复,这些恢复的数据都会保存在SavedStateHandleController对象中的SavedStateHandle属性中,然后在Activity重新创建的时候,会通过反射创建对应的ViewModel对象的时候,将SavedStateHandleController中的SavedStateHandle赋值给对应的ViewModel进行数据恢复。

这块的源码分析可以参考:
从源码看 Jetpack(7)-SavedStateHandle源码详解

这里其实就是直接使用Class的newInstance直接创建对象。Activity和Fragment一般都是使用SavedStateViewModelFactory创建ViewModel对象。

ViewModel的销毁,要分为Activity和Fragment两部分。
首先看下ViewModel在销毁的时候做的事情

而ViewModel的clear()方法的调用,是在ViewModelStore中

Activity的销毁,是通过Lifecycle监听生命周期回调,当生命周期执行到onDestroy的时候,调用ViewModelStore的clear()方法进行ViewModel的销毁。
看ComponentActivity中构造器中的实现:

Fragment的生命周期管理,如下:

Fragment的生命周期,首先会依次增大,然后在从onResume变成onPause的时候,就开始状态码减小。即先升再降的一个状态变化。在当前状态码变成CREATED的时候,就会执行onDestroy。即调用

FragmentStateManager.destroy

在这里就会调用nonConfig.clearNonConfigState方法,nonConfig其实就是FragmentManagerViewModel对象。
FragmentManagerViewModel.clearNonConfigState

按照上面的逻辑,在Activity重建时会执行destory生命周期事件,那么为什么ViewModel没有销毁呢?
其实就是在屏幕旋转的时候,AMS通过Binder回调Activity的retainNonConfigurationInstances()方法,这个时候就会进行数据的保存,保存到一个NonConfigurationInstances对象;而在屏幕翻转结束之后,会再一次调用ViewModelProvider的构造函数,此时就会调用owner.getViewModelStore(),接着就会调用getLastNonConfigurationInstance(),这里就会通过Activity中的NonConfigurationInstances对象取出保存的ViewModelStore对象。
所以数据保存就是通过retainNonConfigurationInstances()方法保存在NonConfigurationInstances对象,而再一次使用取出ViewModel的数据的时候,就是从nc对象中取出ViewModelStore对象,而ViewModelStore对象保存有ViewModel集合
通过对ComponentActivity的getViewModelStore()方法进行分析。可以找到这个问题的答案。

当mViewModelStore为null的时候,会从NonConfigurationInstances中获取ViewModelStore对象。
其实在ComponentActivity和Activity中都会有一个NonConfigurationInstances类,而Activity中的NonConfigurationInstances类结构如下:

这里的Object activity其实就是保存的ComponentActivity中的NonConfigurationInstances类对象,看Activity的下面的方法:

activity这个Object对象,其实是通过onRetainNonConfigurationInstance()方法返回值赋值,而onRetainNonConfigurationInstance()方法的实现是在ComponentActivity中。
看ComponentActivity中的下面方法:

因为这里会在ComponentActivity中的NonConfigurationInstances类对象中保存ViewModelStore对象,所以这也是Activity重建时不会销毁ViewModel的原因。

onRetainNonConfigurationInstance()方法除了被Activity的retainNonConfigurationInstances()调用以外,还会被LocalActivityManager的dispatchRetainNonConfigurationInstance()方法调用

在分析ViewModel的销毁过程时,我们看到Activity与Fragment存储VieModel是分离的,那么同一个Activity下的Fragment是如何共享ViewModel的呢?
其实共享的是Activity的ViewModel。

而具体的实现逻辑,其实就是在FragmentViewModelLazy.kt中的:

在Fragment中可以直接调用,这是一个Fragment的扩展函数,通过实现requireActivity().viewModelStore,获取到了Activity的ViewModelStore对象后,这样就可以实现了Fragment共用Activity的ViewModel,从而实现了Fragment之间共享ViewModel。
Fragment之间共享ViewModel,需要引入

已赞过 已踩过<
你对这个回答的评价是?
评论 收起
ZESTRON
2024-09-04 广告
在Dr. O.K. Wack Chemie GmbH,我们高度重视ZESTRON的表界面分析技术。该技术通过深入研究材料表面与界面的性质,为提升产品质量与可靠性提供了有力支持。ZESTRON的表界面分析不仅涵盖了相变化、化学反应、吸附与解吸... 点击进入详情页
本回答由ZESTRON提供
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式