jetpack白盒化之从ViewModelProvider到ViewModel

188 阅读5分钟

前言

在没有引入viewmodels的kt内联方法之前,创建ViewModel目前常见的做法是在ViewModelStoreOwner内创建ViewModelProvider对象,再去get目标类.现在我们可以以一个完全新接触的视角,从构造方法开始去一点点拓宽了解ViewModel库的体系内容.

image.png

  • ViewModelStoreOwner,我知道,Activity跟Fragment这些嘛,但更多的呢,又好像说不上来
  • ViewModelStore里面长什么样
  • 为什么这里用到了Factory,还是default的,那不default的是什么
  • 同样的,旁边的CreationExtras也有同问

ViewModelProvider

避不开的这个类,类的介绍告知:为作用域提供VM对象的类

image.png

ViewModelStoreOwner和ViewModelStore

接口,提供getViewModelStore抽象方法实现ViewModelStore对象。androidx.activity.ComponentActivity和Fragment都实现了该接口方法。

image.png

  • ComponentActivity从NonConfigurationInstances取,如果没有再new出一个. image.png

  • Fragment:从FragmentManager取(本质找FragmentManagerViewModel取),new出一个对象 image.png

但这里还是不知道这ViewModelStore到底里面是怎样?点开源码

image.png

可以把ViewModelStore当成是一个对map进行操作的类,map里面以String为key,val为ViewModel.从put,get,clear等方法进行操作.只是ViewModelStore作为ViewModelStoreOwner实现类里的必有字段.

从ViewModelProvider的构造方法开始

最简单的api,传个ViewModelStoreOwner进来就行,反正这年头用的不是Fragment就是ComponentActivity对吧.

image.png

defaultFactory

借助defaultFactory方法来获取Factory:

  • 如果ViewModelStoreOwner还是HasDefaultViewModelProviderFactory的实现类的话,将使用ViewModelStoreOwner自有的factory,如ComponentActivity跟Fragment.
  • 否则将使用内置的Factory.

image.png

好的,一个新疑问产生:什么是HasDefaultViewModelProviderFactory?

defaultCreationExtras

image.png

也是和一样defaultFactory方法执行时都套路:ViewModelStoreOwner还是HasDefaultViewModelProviderFactory的实现类的话,将使用ViewModelStoreOwner自有的CreationExtras.

  • 查看得知
  • 默认是CreationExtras.Empty,也就是空 image.png

可以把CreationExtras就当作是map的包装对象.

但HasDefaultViewModelProviderFactory,到底是什么?

HasDefaultViewModelProviderFactory

原来是接口.那哪些类实现了HasDefaultViewModelProviderFactory接口呢?查看继承树,如下图所示:

image.png

原来ComponentActivity跟Fragment作为ViewModelStoreOwner同时,也对HasDefaultViewModelProviderFactory接口进行了实现.

  • ComponentActivity:ComponentActivity用的Factory是SavedStateViewModelFactory,赋值给mDefaultFactory字段,借助其create方法完成对ViewModel的创建 image.png image.png

  • Fragment:最终也是用SavedStateViewModelFactory,赋值给mDefaultFactory字段 image.png image.png

这里出现了ViewModelProvider.Factory,他们之间有什么联系.我们从类信息入手

ViewModelProvider.Factory

注释说得清楚,其职责就是用于初始化ViewModel.这里有两个抽象方法用于具体返回ViewModel实例的.右边看到实现类,关于实例类的内容,待会我们带着问题继续看.

image.png

内置Factory:

NewInstanceFactory

构造函数点击defaultFactory方法,排除实现了HasDefaultViewModelProviderFactory接口的ViewModelStoreOwner类,后默认使用NewInstanceFactory,对Factory接口的create实现为反射传入类的无参构造函数,创建类对象.

image.png

AndroidViewModelFactory

NewInstanceFactory子类.

image.png

create方法判断是否AndroidViewModel的子类

image.png

决定使用目标ViewModel(Application),还是父类处理的使用无参构造函数 image.png

image.png

代理Factory:SavedStateViewModelFactory(ComponentActivity和Fragment依赖的Factory)

类信息和构造方法

image.png

image.png

不光实现了ViewModelProvider.Factory接口,还实现了ViewModelProvider.OnRequeryFactory接口

意外发现,该类内部又有了一个Factory类型属性factory,将根据application==null决定使用ViewModelProvider.AndroidViewModelFactory的有参或者无参构造方法来创建

image.png

这里会开始多个疑问,为什么自己都已经是Factory实现类,为什么又要有一个factory的字段,那什么时候用,毕竟我们已经要实现create方法了不是么?

create(modelClass: Class<T>, extras: CreationExtras): T

image.png

由于ViewModelProvider的get方法里,将key作为内容塞入了CreationExtras中,并传给ViewModelProvider的factory属性的create方法,所以SavedStateViewModelFactory执行到这里的时候取出指定的key是能拿到的.

image.png

判断CreationExtras指定key是否有效,无效则走create(key: String, modelClass: Class<T>): T方法

有效情况下,判断是否作为AndroidViewModel子类,且当前SavedStateViewModelFactory的application字段是否有效:

  • 是就查找目标ViewModel的(Application, SavedStateHandle) 的带参构造函数

  • 不满足就查找ViewModel(SavedStateHandle) 的带参构造函数

如果目标ViewModel未定义上述的带参构造函数,就使用factory的普通create方法(具体create执行逻辑,是AndroidViewModelFactory或者父类NewInstanceFactory的create实现,根据application对象是否为空决定,参考上述ViewModelProvider.AndroidViewModelFactory)

image.png

以ComponentActivity为例子,ComponentActivity在实现HasDefaultViewModelProviderFactory接口是,对defaultViewModelCreationExtras重写,塞入其他内容

image.png

可以认为ComponentActivity执行的是上半部分,但是Fragment没有重写,取不到值,将执行下半部分,调用了create(key: String, modelClass: Class<T>): T方法.

create(key: String, modelClass: Class<T>): T

image.png

同样是根据判断ViewModel类型,查找所用的带参构造函数

判断目标ViewModel是否属于AndroidViewModel类型,且判断application字段是否为空.决定查找目标ViewModel的(Application, SavedStateHandle) 还是目标ViewModel的(SavedStateHandle)

查找构造函数结果,目标的ViewModel存在指定参数的构造函数去反射创建对象,为空情况使用类名调用create方法:

  • 使用factory(如AndroidViewModelFactory)
  • instance(NewInstanceFactory类)的create方法

image.png

好的,现在知道create都干了什么事,那create方法什么时候用呢?ViewModelProvider的get方法.

image.png

结论

在ComponentActivity跟Fragment会使用SavedStateViewModelFactory作为管理对象,对于前面提到的为什么又包了层Factory,其实就是代理模式里的静态代理实现.

执行create方法时,根据Application参数的是否为null,以及目标ViewModel类所声明构造函数的参数列表来决定:

对于继承自AndroidViewModel的ViewModel类,将按照如下的构造方法顺序查找并反射对象: 1. (Application, SavedStateHandle) 2. (SavedStateHandle) 3. (application: Application) 4. 无参构造

无参构造将作为兜底的方式来实现

Factory的优先级上:

  1. AndroidViewModelFactory(如果需要Application或者SavedStateHandle)
  2. NewInstanceFactory(无参)

ViewModelStore和CreationExtras就当作是个map的管理对象,只是一个管理的是ViewModel实例,一个是存key