viewmodel创建及使用分析

1、相关的类

  • ViewModelStore :管理viewModel实例,内部包含一个Map用来存储viewmodel,内部包括put、get、clear等方法
  • ViewModelProvider :管理ViewModelStore和Factory,Factory里面有create方法是创建对应的viewmodel的,ViewModelProvider内部有一个get方法获取viewmodel

2、在项目中应用

首先新建项目分别创建TestViewModel
TestViewModel.class

fun provideFactory(repository: TestRepository): ViewModelProvider.Factory = object : ViewModelProvider.Factory {@Suppress("UNCHECKED_CAST")override fun <T : ViewModel> create(modelClass: Class<T>): T {return TestViewModel(repository) as T}}

MainActivity.class中初始化代码:

    private val testViewModel by viewModels<TestViewModel> {TestViewModel.provideFactory(TestRepository())}

接下来在MainActivity里面就可以正常使用这个viewmodel了

3、流程简单解析

首先我们在mainActivity里面初始化时候使用了by viewmodel 这个方式进行初始化点击进入这个方法之后源码如下:

public inline fun <reified VM : ViewModel> ComponentActivity.viewModels(noinline extrasProducer: (() -> CreationExtras)? = null,noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {val factoryPromise = factoryProducer ?: {defaultViewModelProviderFactory}return ViewModelLazy(VM::class,{ viewModelStore },factoryPromise,{ extrasProducer?.invoke() ?: this.defaultViewModelCreationExtras })
}

可以看到viewModels是ComponentActivity的一个扩展函数,参数需要传factoryProducer,factoryProducer就是前面我们提到过的ViewModelProvider的内部的一个factory类,用来创建viewModel的,所以我们传入TestViewModel.provideFactory。
继续向下看进入ViewModelLazy:

public class ViewModelLazy<VM : ViewModel> @JvmOverloads constructor(private val viewModelClass: KClass<VM>,private val storeProducer: () -> ViewModelStore,private val factoryProducer: () -> ViewModelProvider.Factory,private val extrasProducer: () -> CreationExtras = { CreationExtras.Empty }
) : Lazy<VM> {private var cached: VM? = nulloverride val value: VMget() {val viewModel = cachedreturn if (viewModel == null) {val factory = factoryProducer()val store = storeProducer()ViewModelProvider(store,factory,extrasProducer()).get(viewModelClass.java).also {cached = it}} else {viewModel}}override fun isInitialized(): Boolean = cached != null
}

首先判断是否有缓存,如果有缓存直接返回,无缓存情况下就去ViewModelProvider获取对应的viewmodel并且进行一下缓存操作,接下来我们看一下ViewModelProvider的get方法

    public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {val viewModel = store[key]if (modelClass.isInstance(viewModel)) {(factory as? OnRequeryFactory)?.onRequery(viewModel!!)return viewModel as T} else {@Suppress("ControlFlowWithEmptyBody")if (viewModel != null) {// TODO: log a warning.}}val extras = MutableCreationExtras(defaultCreationExtras)extras[VIEW_MODEL_KEY] = key// AGP has some desugaring issues associated with compileOnly dependencies so we need to// fall back to the other create method to keep from crashing.return try {factory.create(modelClass, extras)} catch (e: AbstractMethodError) {factory.create(modelClass)}.also { store.put(key, it) }}

get方法通过内部的store传入类名来获取view model,那么store是从哪里来的呢?往回看能看到是在ComponentActivity.viewModels这里返回了一个ViewModelLazy时传入了viewModelStore,这个viewModelStore是从ComponentActivity初始化时候就创建了的

    public ComponentActivity() {//......getLifecycle().addObserver(new LifecycleEventObserver() {@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {if (event == Lifecycle.Event.ON_DESTROY) {// Clear out the available contextmContextAwareHelper.clearAvailableContext();// And clear the ViewModelStoreif (!isChangingConfigurations()) {getViewModelStore().clear();}mReportFullyDrawnExecutor.activityDestroyed();}}});getLifecycle().addObserver(new LifecycleEventObserver() {@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {ensureViewModelStore();getLifecycle().removeObserver(this);}});//......}void ensureViewModelStore() {if (mViewModelStore == null) {NonConfigurationInstances nc =(NonConfigurationInstances) getLastNonConfigurationInstance();if (nc != null) {// Restore the ViewModelStore from NonConfigurationInstancesmViewModelStore = nc.viewModelStore;}if (mViewModelStore == null) {mViewModelStore = new ViewModelStore();}}}

在activity创建时添加生命周期监听,生命周期变更时创建ViewModelStore,当生命周期destory时会通过isChangingConfigurations来判断是否是通过切换横竖屏导致的destroy,如果是的话不会对view model执行clear,这样保证了view model在切换横竖屏时依然可以保存数据,等页面真正的退出执行的destroy时才会对viewmodel执行clear方法,这样保证了viewmodel的生命周期和activity一致,也不需要我们单独对其生命周期进行维护。

针对这个流程简单的分析,如有分析不符的地方欢迎评论指正

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/44923.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Facebook的未来蓝图:从元宇宙到虚拟现实的跨越

随着科技的不断演进和社会的数字化转型&#xff0c;虚拟现实&#xff08;VR&#xff09;和增强现实&#xff08;AR&#xff09;作为下一代计算平台正逐渐走进人们的视野。作为全球领先的科技公司之一&#xff0c;Facebook正在积极探索并推动这一领域的发展&#xff0c;以实现其…

嫌云服务器太贵,使用内网穿透代替

企业与个人开发者常常面临一个现实问题&#xff1a;高昂的云服务器成本。随着业务需求的增长&#xff0c;持续的服务器租赁费用可能成为负担。然而&#xff0c;在这个充满创新的时代&#xff0c;一种名为“内网穿透”的技术正逐渐成为解决这一难题的优选方案。本文将探讨内网穿…

深度学习基础与实战:Python实现

深度学习基础与实战&#xff1a;Python实现 深度学习是机器学习的一个重要分支&#xff0c;通过多层神经网络实现对数据的自动特征提取和建模。本文将介绍深度学习的基础概念、常用框架以及一个完整的实战项目&#xff0c;帮助读者从基础入门到实际应用。 目录 深度学习概述…

CF 1986D. Mathematical Problem

原题链接&#xff1a;Problem - 1986D - Codeforces 题意&#xff1a;一串长度最多为20的由数字组成的字符串&#xff0c;在这些数字中间可以添加字符串长度减去二数量的符号&#xff0c;加或者乘&#xff0c;例如1234&#xff0c;就可以添加加号或者乘号二个&#xff0c;变成…

vue中el-table前端导出excel数据表格

一、el-table为正常时&#xff0c;导出方法如下&#xff1a; 1.添加导出按钮 <el-button class"greenLinearbg dc" size"small" click"webExportTotalExcel()" v-if"totalBillShow">导出</el-button>2.导出方法 // we…

Spring开发实践(二)

EnableAsync 和 Async 注解的使用方法 EnableAsync 和 Async 是Spring框架中的两个注解&#xff0c;用于启用和使用异步方法执行。它们可以帮助你在Spring应用程序中实现异步编程&#xff0c;从而提高应用程序的性能和响应速度。 EnableAsync EnableAsync 注解用于启用Sprin…

ARM Ubuntu 主机安装指定版本Python

要在你的ARM Linux主机上安装Python 3.12&#xff0c;你可以从源码编译安装。以下是具体步骤&#xff1a; 步骤1&#xff1a;安装依赖 首先&#xff0c;确保你有必要的编译工具和依赖包&#xff1a; sudo apt-get update sudo apt-get install -y build-essential libssl-d…

【每日一练】python的类.对象.成员.行为.方法传参综合实例(保姆式教学)

运行结果: 本节课程内容&#xff1a;类的使用 1.掌握类的定义和使用方法 2.掌握类的成员的方法使用 3.掌握self关键字的作用 4.定义在类里的函数是类的一种行为&#xff0c;叫方法 5.带传参的行为使用方法 类基本分两部分组成&#xff1a;1.属性,2.方法 类的使用语法&#xf…

springCloud整合Dubbo案例

前言&#xff1a; 好久没有使用dubbo了&#xff0c;温习一下。 一、先搭建一个SpringCloud框架 整体框架如下图 1. 先创建一个父工程&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4…

开发者必读:获取电商API的多种渠道

开发电商软件往往需要对接电商API&#xff0c;电商API可以从哪些渠道获取&#xff1f;下面给大家介绍两种获取渠道。 一、从电商平台开放平台获取电商API 电商平台的开放平台是获取电商API最直接的渠道&#xff0c;但是电商平台较多&#xff0c;每一个电商平台都需要单…

Vue3 引入腾讯地图 包含标注简易操作

1. 引入腾讯地图API JavaScript API | 腾讯位置服务 (qq.com) 首先在官网注册账号 并正确获取并配置key后 找到合适的引入方式 本文不涉及版本操作和附加库 据体引入参数参考如下图 具体以链接中官方参数为准标题 在项目根目录 index.html 中 写入如下代码 <!-- 引入腾…

Socks5代理为什么比HTTP代理快?

在数字化日益深入的时代&#xff0c;网络安全和隐私保护成为了公众关注的焦点。为了应对网络威胁&#xff0c;保护个人隐私和数据安全&#xff0c;代理技术应运而生。在众多代理协议中&#xff0c;SOCKS5代理和HTTP代理是两种较为常见的选择。然而&#xff0c;为何SOCKS5代理在…

网页设计零基础入门:前端技术全攻略

在当今互联网飞速发展的时代&#xff0c;前端网页设计已经成为一个备受关注的领域。随着其重要性的不断提高&#xff0c;越来越多的专业人士和爱好者开始对前端设计感兴趣&#xff0c;希望通过掌握这项技术开辟自己的职业道路。然而&#xff0c;对于新手设计师来说&#xff0c;…

ollama + lobechat 搭建自己的多模型助手

背景 人工智能已经推出了快2年了&#xff0c;各种模型和插件&#xff0c;有渐渐变成熟的趋势&#xff0c;打造一个类似 hao123网站的人工智能模型入口&#xff0c;也变得有需求了。用户会去比较多个ai给出的答案&#xff0c;作为程序员想拥有一台自己的GPU服务器来为自己服务。…

如何在vue的项目中导入阿里巴巴图标库

阿里巴巴矢量图标库官网&#xff1a;iconfont-阿里巴巴矢量图标库 选择你喜欢的图标&#xff0c;添加入库 点击添加至项目&#xff0c;并新建文件夹&#xff0c;点击确定 选择font-class&#xff0c;点击生成代码 代码生成后&#xff0c;在网站上打开 全选复制到style 点击复制…

【TB作品】MSP430F6638单片机,频率计

基于 MSP430-FFTB6638 实验箱 频率测量与通信系统 利用 MCU 定时器模块相关功能设计实现数字频率计功能&#xff0c;测量范围&#xff1a;100~10000Hz&#xff0c; 测量误差≤1%&#xff0c;测量速度≤1 秒。测量结果本地显示&#xff08;段式 LCD、字符型 LCD、点阵 LCD &…

springboot系列九: 接收参数相关注解

文章目录 基本介绍接收参数相关注解应用实例PathVariableRequestHeaderRequestParamCookieValueRequestBodyRequestAttributeSessionAttribute 复杂参数基本介绍应用实例 自定义对象参数-自动封装基本介绍应用实例 基本介绍 1.SpringBoot 接收客户端提交数据 / 参数会使用到相…

【小白也能看的懂】想要玩转AI大模型,这4招你得知道

前言 对于大部分人来说&#xff0c;能够灵活使用AI工具&#xff0c;并对自己每个常用的AI工具优劣势很清楚&#xff0c;就已经足够了。不过&#xff0c;毕竟AI发展实在太快&#xff0c;多了解一些相关的知识点&#xff0c;以全局的视角去看AI&#xff0c;可以避免管中窥豹&…

编程语言现状:深入剖析与未来展望

编程语言现状&#xff1a;深入剖析与未来展望 在数字化时代的浪潮中&#xff0c;编程语言作为信息科技领域的基石&#xff0c;正经历着前所未有的变革与发展。本文将从四个方面、五个方面、六个方面和七个方面&#xff0c;深入剖析编程语言的现状&#xff0c;并展望其未来的发…

【错题集-编程题】买卖股票的最好时机(四)(动态规划)

力扣对应题目链接&#xff1a;188. 买卖股票的最佳时机 IV - 力扣&#xff08;LeetCode&#xff09; 牛客对应题目链接&#xff1a;买卖股票的最好时机(四)_牛客题霸_牛客网 (nowcoder.com) 一、分析题目 1、状态表示 为了更加清晰的区分买入和卖出&#xff0c;我们换成有股…