ViewModel
首先看下ViewModel的结构。
ViewModel类结构简单,是一个抽象类,我们使用时候,需要继承该类,来定义我们自己的ViewModel。内部定义的onCleared方法会在clear方法中被调用。
clear方法可以被外部调用,当被调用时候,可以触发onCleared方法。
我们暂时可以只关注这么多,继续向后分析。
AndroidViewModel
AndroidViewModel继承自ViewModel,内部只是包含了一个变量application可供我们使用。
生成ViewModel实例
实际使用ViewModel过程中,我们需要拿到viewModel对象进行操作。拿取viewModel对象实例分几种方法,我们依次分析下。
方法1:NewInstanceFactory
使用方法:
arduino
ViewModelProvider.NewInstanceFactory.instance.create(CustomViewModel::class.java)
从使用方法可以看到,直接使用的是NewInstanceFactory中的instance对象的方法create来创建viewModel。我们看下这个instance和create方法。
根据源码红框逻辑可以知道,instance在当前进程中存在唯一性,是个单例对象。
它的create方法也很简单,通过反射new一个实例出来,所以该方法每次调用都会生成一个新的viewModel对象出来。
方法1 特点总结
- 每次生成的viewModel都是一个单独的新对象
- 该方法生成的viewModel不会和任何view或activity或fragment的生命周期有关联。作用域没了后,对象会被回收。
- onCleared方法永远不会被触发,因为没有地方会调用其clear方法
方法2:AndroidViewModelFactory
如何使用
scss
ViewModelProvider.AndroidViewModelFactory.getInstance(application).create(CustomViewModel::class.java)
AndroidViewModelFactory继承自NewInstanceFactory,AndroidViewModelFactory要求必须传入一个Applciation。
getInstance(application)也是一个单例对象,APP进程内存活。
create方法对外暴露了两种入参方式:
其中第一种方法,允许传入外部我们自定义的一个CreationExtra对象,这个CreationExtra其实本意是为了封装一些我们实例化时候需要传给ViewModelde 入参。这里是将application传入了进来。
对于第二种方法和NewInstanceFactory一样,直接生成一个viewModel对象实例返回。
方法2 特点总结
- 每次生成的viewModel都是一个单独的新对象
- 该方法生成的viewModel不会和任何view或activity或fragment的生命周期有关联。作用域没了后,对象会被回收。
- onCleared方法永远不会被触发,因为没有地方会调用其clear方法
- 允许我们传入自定义的CreateExtra对象,但是没啥用
- 内部会维护一个application对象
方法3:ViewModelProvider
如何使用
scss
ViewModelProvider(activity)[ActivityMainViewModel::class.java]
ViewModelProvider(fragment)[ActivityMainViewModel::class.java]
ViewModelProvider也具有三个构造函数,允许我们传入一个ViewModelStoreOwner对象。AndroidX的activity和fragment都有实现这个接口,所以这里我们可以直接传入activity或者fragment对象。
activity和fragment都会创建自己的CreationExtra对象用于存储生成的viewModel对象。所以我们通过该方式获取到的viewModel是同一个对象。
ViewModelStoreOwner
ViewModelStoreOwner 接口需要实现者返回一个ViewModelStore对象。看下ViewModelStore对象结构:
该对象中会维护一个Map,map保存的是key和viewModel的映射关系。所以对于activity和fragment实现了该接口,他们会创建自己的ViewModelStore对象,用于保存创建好的viewModel对象到map中。从而实现了每次通过同一个activity对象实例获取到的viewModel都是同一个。
这个是activity实现了接口ViewModelStore的源码,可以看到返回了一个ViewModelStore对象实例并保存到了当前对象中。从而证实了我们上述理念。
我们理清了内部大致架构原理,我们接下来从get方法入手,具体看下调动流程:
- 实例化ViewModelProvider时候,传入一个activity
- 调用ViewModelProvider的get方法获取viewModel
- 从ViewModelStore中的map中查找对应的viewmodel,找到则返回
- 找不到则新建
- 同时从CreationExtra中读取参数调用factory的create方法创建viewModel
clear方法
从源码中可以直接看到,当activity的onDestory被调用后,会调用ViewModelStore的clear方法,清空当前map集合中保存的所有viewModel。
- 关于ViewModelProvider的几个入参
- ViewModelProvider中的factory用于定义创建ViewModel的方式方法,比如是否传入参application等等。
- ViewModelStoreOwn用于保存viewModel和其映射。
- CreationExtra传递入参,用于创建viewModel时候factory使用
- 架构
- 关于传递context引起的内存泄露
- 我们如果直接通过上述方法1和方法2来创建viewModel,那么这个viewModel其实就是一个单例对象,可以在APP生命周期内任何地方使用,如果我们传入context,那么context便存在无法被正常释放的情况。
- 通过方法3生成的viewModel,虽然存储于activity中,但是当activity销毁时候,只是将activity中保存的map进行了清空,而viewModel对象实例仍然可能在运行中,此时如果持有context,仍然会造成泄露。