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,仍然会造成泄露。
相关推荐
拭心11 小时前
Google 提供的 Android 端上大模型组件:MediaPipe LLM 介绍
android
带电的小王13 小时前
WhisperKit: Android 端测试 Whisper -- Android手机(Qualcomm GPU)部署音频大模型
android·智能手机·whisper·qualcomm
梦想平凡13 小时前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
元争栈道14 小时前
webview和H5来实现的android短视频(短剧)音视频播放依赖控件
android·音视频
阿甘知识库14 小时前
宝塔面板跨服务器数据同步教程:双机备份零停机
android·运维·服务器·备份·同步·宝塔面板·建站
元争栈道15 小时前
webview+H5来实现的android短视频(短剧)音视频播放依赖控件资源
android·音视频
MuYe15 小时前
Android Hook - 动态加载so库
android
居居飒16 小时前
Android学习(四)-Kotlin编程语言-for循环
android·学习·kotlin
Henry_He19 小时前
桌面列表小部件不能点击的问题分析
android
工程师老罗19 小时前
Android笔试面试题AI答之Android基础(1)
android