ViewModel源码解析

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 特点总结
  1. 每次生成的viewModel都是一个单独的新对象
  2. 该方法生成的viewModel不会和任何view或activity或fragment的生命周期有关联。作用域没了后,对象会被回收。
  3. 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 特点总结
  1. 每次生成的viewModel都是一个单独的新对象
  2. 该方法生成的viewModel不会和任何view或activity或fragment的生命周期有关联。作用域没了后,对象会被回收。
  3. onCleared方法永远不会被触发,因为没有地方会调用其clear方法
  4. 允许我们传入自定义的CreateExtra对象,但是没啥用
  5. 内部会维护一个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方法入手,具体看下调动流程:

  1. 实例化ViewModelProvider时候,传入一个activity
  2. 调用ViewModelProvider的get方法获取viewModel
  3. 从ViewModelStore中的map中查找对应的viewmodel,找到则返回
  4. 找不到则新建
  5. 同时从CreationExtra中读取参数调用factory的create方法创建viewModel
clear方法

从源码中可以直接看到,当activity的onDestory被调用后,会调用ViewModelStore的clear方法,清空当前map集合中保存的所有viewModel。

  • 关于ViewModelProvider的几个入参
  1. ViewModelProvider中的factory用于定义创建ViewModel的方式方法,比如是否传入参application等等。
  2. ViewModelStoreOwn用于保存viewModel和其映射。
  3. CreationExtra传递入参,用于创建viewModel时候factory使用
  • 架构
  • 关于传递context引起的内存泄露
  1. 我们如果直接通过上述方法1和方法2来创建viewModel,那么这个viewModel其实就是一个单例对象,可以在APP生命周期内任何地方使用,如果我们传入context,那么context便存在无法被正常释放的情况。
  2. 通过方法3生成的viewModel,虽然存储于activity中,但是当activity销毁时候,只是将activity中保存的map进行了清空,而viewModel对象实例仍然可能在运行中,此时如果持有context,仍然会造成泄露。
相关推荐
Winston Wood2 小时前
Android Parcelable和Serializable的区别与联系
android·序列化
清风徐来辽2 小时前
Android 项目模型配置管理
android
帅得不敢出门2 小时前
Gradle命令编译Android Studio工程项目并签名
android·ide·android studio·gradlew
problc3 小时前
Flutter中文字体设置指南:打造个性化的应用体验
android·javascript·flutter
帅得不敢出门13 小时前
安卓设备adb执行AT指令控制电话卡
android·adb·sim卡·at指令·电话卡
我又来搬代码了15 小时前
【Android】使用productFlavors构建多个变体
android
德育处主任17 小时前
Mac和安卓手机互传文件(ADB)
android·macos
芦半山17 小时前
Android“引用们”的底层原理
android·java
迃-幵17 小时前
力扣:225 用队列实现栈
android·javascript·leetcode
大风起兮云飞扬丶17 小时前
Android——从相机/相册获取图片
android