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,仍然会造成泄露。
相关推荐
安东尼肉店4 小时前
Android compose屏幕适配终极解决方案
android
2501_916007474 小时前
HTTPS 抓包乱码怎么办?原因剖析、排查步骤与实战工具对策(HTTPS 抓包乱码、gzipbrotli、TLS 解密、iOS 抓包)
android·ios·小程序·https·uni-app·iphone·webview
feiyangqingyun6 小时前
基于Qt和FFmpeg的安卓监控模拟器/手机摄像头模拟成onvif和28181设备
android·qt·ffmpeg
用户20187928316710 小时前
ANR之RenderThread不可中断睡眠state=D
android
煤球王子10 小时前
简单学:Android14中的Bluetooth—PBAP下载
android
小趴菜822710 小时前
安卓接入Max广告源
android
齊家治國平天下10 小时前
Android 14 系统 ANR (Application Not Responding) 深度分析与解决指南
android·anr
ZHANG13HAO10 小时前
Android 13.0 Framework 实现应用通知使用权默认开启的技术指南
android
【ql君】qlexcel10 小时前
Android 安卓RIL介绍
android·安卓·ril
写点啥呢10 小时前
android12解决非CarProperty接口深色模式设置后开机无法保持
android·车机·aosp·深色模式·座舱