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,仍然会造成泄露。
相关推荐
应用市场3 小时前
离线小游戏做“每日挑战”:日期当随机种子,整局存成 JSON,再加一个“我不是机器人”
android·kotlin·游戏开发
一铭111994 小时前
海豹办公 1.9.15 跨端办公软件实践 文档兼容 Access 数据库与移动 WebView 排错
android·数据库·electron·开源软件·access
geats人山人海5 小时前
java 7异常
android·java·开发语言
2601_962071006 小时前
Kimi K3 vs DeepSeek V4-Pro实测对比:2026年同一入口十道题,耗时与token消耗差在哪
android·java·数据库
右手吉他7 小时前
高通平台IA APN问题分析之二
android·物联网
夜雪一千7 小时前
MySQL 自增 ID 的底层原理与坑点
android·mysql·adb
不浪费一个字节8 小时前
一个纯 Python 实现的 APK 解析与设备操控工具箱
android
itmigrate8 小时前
PHP 导出大 CSV 时内存溢出的一次排查
android·开发语言·php
hai_android8 小时前
LiveEventBusCore 跨 Activity 通讯源码解析
android·kotlin·android jetpack
维克兜率天8 小时前
【维克】统计套利建模:从因子到信号的完整流程
android·开发语言·python·算法·kotlin