故城县网站建设服务商业网站开发

web/2025/10/8 13:58:39/文章来源:
故城县网站建设服务,商业网站开发,制作网站南京,线上投票怎么弄Android Jetpack组件架构#xff1a;ViewModel的原理 导言 本篇文章是关于介绍ViewModel的#xff0c;由于ViewModel的使用还是挺简单的#xff0c;这里就不再介绍其的基本应用#xff0c;我们主要来分析ViewModel的原理。 ViewModel的生命周期 众所周知#xff0c;一般…Android Jetpack组件架构ViewModel的原理 导言 本篇文章是关于介绍ViewModel的由于ViewModel的使用还是挺简单的这里就不再介绍其的基本应用我们主要来分析ViewModel的原理。 ViewModel的生命周期 众所周知一般使用ViewModel是用来解决两个问题的第一个就是关于设备配置发生改变时Activity先前状态的保存在ViewModel出来之前我们一般会使用saveInstanceState这个Bundle来进行状态的保存但是这样做能存储的数据是有限的结构也不够明确ViewModel作为一个生命周期大于Activity的组件就可以帮我们实现状态的存储下面是ViewModel生命周期与Activity对比的图 可以看到直到Activity被完全Destory时ViewModel中的数据才会被清除。 我们使用ViewModel的第二个原因就是用来实现MVVM架构可以通过DataBinding组件和ViewModel组件以及LiveData组件一起实现MVVM架构这样可以减轻Activity的职责避免Activity过于臃肿。 获得ViewModel的提供者 我们从ViewModel的创建开始分析其原理这里用我们上一篇文章的例子 mViewModel ViewModelProvider(this).get(SimpViewModel::class.java)这里首先会通过ViewModelProvider的构造方法获得一个ViewModelProvider的实例其构造方法如下所示 public constructor(owner: ViewModelStoreOwner ) : this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))constructor(private val store: ViewModelStore,private val factory: Factory,private val defaultCreationExtras: CreationExtras CreationExtras.Empty, )可以看到我们调用的是第一个构造方法最终会调用到第二个构造方法中也就是主构造方法中这个构造来说就是指定了三个成员变量分别是ViewModelStore,Factory和CreationExtras三个类型的参数我们先来分别介绍一下这三个类型。 ViewModelStore – ViewModel的拥有者 着整个类比较小但是也是有注释的我们先来看看注释 这段注释中比较重要的信息就是ViewModel是真正用来存储ViewModel的类并且在configuration changes就是配置发生改变时新的实例和旧的实例中的信息是一致的。只有当持有者不再会被recreated时里面的数据才会通过clear清除。 接下来我们来看该类的源码 public class ViewModelStore {private final HashMapString, ViewModel mMap new HashMap();final void put(String key, ViewModel viewModel) {ViewModel oldViewModel mMap.put(key, viewModel);if (oldViewModel ! null) {oldViewModel.onCleared();}}final ViewModel get(String key) {return mMap.get(key);}SetString keys() {return new HashSet(mMap.keySet());}public final void clear() {for (ViewModel vm : mMap.values()) {vm.clear();}mMap.clear();} }可以看到具体是用一个哈希表来存储viewModel的实例的里面唯一比较大的方法就是put方法里面做的处理就是将替换出来的旧的viewModel实例给清理掉。 Factory – ViewModel的创建工厂 这个Factory是一个定义在ViewModelProvider的内部接口它的主要职责是用来初始化ViewModel说实话就是一个工厂。我们来看其定义 public interface Factory {public fun T : ViewModel create(modelClass: ClassT): T {throw UnsupportedOperationException(Factory.create(String) is unsupported. This Factory requires CreationExtras to be passed into create method.)}public fun T : ViewModel create(modelClass: ClassT, extras: CreationExtras): T create(modelClass)companion object {JvmStaticfun from(vararg initializers: ViewModelInitializer*): Factory InitializerViewModelFactory(*initializers)}}不过这里是一个抽象的我们来找一个具体的也就是defaultFactory方法获取的工厂 public companion object {internal fun defaultFactory(owner: ViewModelStoreOwner): Factory if (owner is HasDefaultViewModelProviderFactory)owner.defaultViewModelProviderFactory else instance...... }这个方法的逻辑就是判断ViewModel的持有者是不是有默认的工厂方法如果有的话就获取持有者的默认工厂否则返回的是自身的instance实例至于这个instance实例是在NewInstanceFactory这个实现了Factory接口的工厂类中定义的伴生变量具体逻辑是 JvmStatic public val instance: NewInstanceFactoryRestrictTo(RestrictTo.Scope.LIBRARY_GROUP)get() {if (sInstance null) {sInstance NewInstanceFactory()}return sInstance!!}可以看到instance是一个静态的单例他具体指向的还是这个NewInstanceFactory类至于它是如何初始化/创建ViewModel的实例的我们可以看一眼它的create方法 override fun T : ViewModel create(modelClass: ClassT): T {return try {modelClass.newInstance()} catch (e: InstantiationException) {throw RuntimeException(Cannot create an instance of $modelClass, e)} catch (e: IllegalAccessException) {throw RuntimeException(Cannot create an instance of $modelClass, e)} }这个传入的modelClass就是我们传入的.class文件 ViewModelProvider(this).get(SimpViewModel::class.java)所以可以看到这个默认情况下的工厂就是直接用反射生成了对应ViewModel的实例。 CreationExtras – 构建ViewModel时的额外参数 首先我们来看一看注释的内容 简单来说它就是为工厂生成实例的时候提供额外参数的这些参数使用一个Map来存储的了不过默认情况下我们并不需要实现额外的工厂所以这个类型我们先略过。 获得ViewModel的实例 前面我们已经知道了通过构造ViewModelProvider我们可以获得其Factory了接下来继续向下看 ViewModelProvider(this).get(SimpViewModel::class.java)我们看一看get方法做了什么 public open operator fun T : ViewModel get(modelClass: ClassT): T {val canonicalName modelClass.canonicalName?: throw IllegalArgumentException(Local and anonymous classes can not be ViewModels)return get($DEFAULT_KEY:$canonicalName, modelClass)}public open operator fun T : ViewModel get(key: String, modelClass: ClassT): 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] keyreturn try {factory.create(modelClass, extras)} catch (e: AbstractMethodError) {factory.create(modelClass)}.also { store.put(key, it) }}可以看到第一个方法会调用第二个方法其中第一个方法向第二个方法传入的的第一个String类型的参数是通过DEFAULT_KEY和我们传入的类的类名拼接而成的。然后跳转到第二个方法之中去首先会尝试从ViewModleStroe中获取对应Key对应的ViewModel但是一般第一次创建时应该会为null所以之后跳转的应该是最后return块中的factory.create方法之中这个方法我们在之前Factory的介绍中提到过了具体就是通过反射实例化ViewModel的并且最后将其放入到ViewModelStore对象之中去。 至于多次获取同一个ViewModel实例是会跳转到 if (modelClass.isInstance(viewModel)) {(factory as? OnRequeryFactory)?.onRequery(viewModel)return viewModel as T} 这一段中去这里onRequery默认是无实现的也就是说并不会对viewModel做任何的处理。 ViewModelStore在哪里被创建 既然ViewModel是被存储在ViewModelStore之中的那ViewModelStore究竟是在哪里被创建出来的呢我们可以在ComponentActivity之中找到答案 public ViewModelStore getViewModelStore() {if (getApplication() null) {throw new IllegalStateException(Your activity is not yet attached to the Application instance. You cant request ViewModel before onCreate call.);}ensureViewModelStore();return mViewModelStore; }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(); //创建一个新的ViewModelStore}} }可以看到这里在获得ViewModelStore时主要是通过一个NonConfigurationInstances 而该参数是一个静态的对象也就是说它是一个单例这样就保证了Activity在整个生命周期之中只有一个ViewModelStore实例从而实现配置改变时也可以恢复数据的作用。 Activity的默认工厂 在看ComponentActivity的源码时发现了原来Activity也是有默认工厂的它的具体实现如下 constructor(application: Application?, owner: SavedStateRegistryOwner, defaultArgs: Bundle?) {savedStateRegistry owner.savedStateRegistrylifecycle owner.lifecyclethis.defaultArgs defaultArgsthis.application applicationfactory if (application ! null) getInstance(application)else ViewModelProvider.AndroidViewModelFactory()}这个方法最终设置到的工厂类都是一个名为AndroidViewModelFactory的工厂类 public open class AndroidViewModelFactoryprivate constructor(private val application: Application?,// parameter to avoid clash between constructors with nullable and non-nullable// ApplicationSuppress(UNUSED_PARAMETER) unused: Int,) : NewInstanceFactory() {Suppress(SingletonConstructor)public constructor() : this(null, 0)Suppress(SingletonConstructor)public constructor(application: Application) : this(application, 0)Suppress(DocumentExceptions)override fun T : ViewModel create(modelClass: ClassT, extras: CreationExtras): T {return if (application ! null) {create(modelClass)} else {val application extras[APPLICATION_KEY]if (application ! null) {create(modelClass, application)} else {// For AndroidViewModels, CreationExtras must have an application setif (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {throw IllegalArgumentException(CreationExtras must have an application by APPLICATION_KEY)}super.create(modelClass)}}}Suppress(DocumentExceptions)override fun T : ViewModel create(modelClass: ClassT): T {return if (application null) {throw UnsupportedOperationException(AndroidViewModelFactory constructed with empty constructor works only with create(modelClass: ClassT, extras: CreationExtras).)} else {create(modelClass, application)}}Suppress(DocumentExceptions)private fun T : ViewModel create(modelClass: ClassT, app: Application): T {return if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {//如果传入的Class类型实现的接口和AndroidViewModel::class一致及说明也有生命周期调用构造犯法并且传入application对象try {modelClass.getConstructor(Application::class.java).newInstance(app)} catch (e: NoSuchMethodException) {throw RuntimeException(Cannot create an instance of $modelClass, e)} catch (e: IllegalAccessException) {throw RuntimeException(Cannot create an instance of $modelClass, e)} catch (e: InstantiationException) {throw RuntimeException(Cannot create an instance of $modelClass, e)} catch (e: InvocationTargetException) {throw RuntimeException(Cannot create an instance of $modelClass, e)}} else super.create(modelClass)}public companion object {internal fun defaultFactory(owner: ViewModelStoreOwner): Factory if (owner is HasDefaultViewModelProviderFactory)owner.defaultViewModelProviderFactory else instanceinternal const val DEFAULT_KEY androidx.lifecycle.ViewModelProvider.DefaultKeyprivate var sInstance: AndroidViewModelFactory? nullJvmStaticpublic fun getInstance(application: Application): AndroidViewModelFactory {if (sInstance null) {sInstance AndroidViewModelFactory(application)}return sInstance!!}private object ApplicationKeyImpl : KeyApplicationJvmFieldval APPLICATION_KEY: KeyApplication ApplicationKeyImpl}}具体通过getInstance方法就跳转到了这里可以发现似乎工厂类都是一个单例的模式这个工厂的特殊之处就是他的create方法涉及到了Application对象的传入比如说这里的newInstance方法 modelClass.getConstructor(Application::class.java).newInstance(app)public T newInstance(Object ... initargs)throws InstantiationException, IllegalAccessException,IllegalArgumentException, InvocationTargetException {if (serializationClass null) {return newInstance0(initargs);} else {return (T) newInstanceFromSerialization(serializationCtor, serializationClass);} }也就是说整个被传入Application的生命周期内都只有一个实例这样由于创建的实例在生命周期范围内的单例性和ViewModelStore的单例性整个ViewModel就可以实现在整个Activity的生命周期内(发生意外比如说配置改变时)数据不变更的作用。

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

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

相关文章

张家口建站优化可以推广发广告的app

Fiber 上篇文章fiber简单理解记录了react fiber架构,Hooks是基于fiber链表来实现的。阅读以下内容时建议先了解react fiber。 jsx -> render function -> vdom -> fiber树 -> dom vdom 转 fiber 的过程称为 recocile。diff算法就是在recocile这个过程…

济宁祥云网站建设360弹出网站

django部署在iis下,webconfig错误错误原因:iis7以后,web.config管理机制更安全了默认情况下,会锁住配置项,不许修改怎么办?如何求解以上问题呢?D:django_websiteshello>%windir%C:Windows 不…

花木网站建设龙华网站建设设计公司

当MySQL使用Unix Socket启动时,直接使用localhost会发生了一个数据库错误,发生无法连接数据库错误。 Warning: mysql_connect() [function.mysql-connect]: [2002] 这时应当修改hostname,例如在CI 配置数据库 (database.php) 从: …

建立企业网站的技能wordpress扁平主题

首先唱名(do、re、mi、fa、sol、la、si 1234567)先对应在 小字一组上,一般调号 1c 时都是对应在 小字一组上 然后从 小字一组 开始往左或往右,往左的音是越低的,往右的音是越高的,这时也需要给唱名&#xf…

鞍山最新消息动态ip做网站影响seo吗

题目描述 mobiusp 创作了一首 n 个音符的乐曲,其中第 iii 个音符的音高为 ai​ ,但是 mobiusp 对以前的创作风格和黑历史很不满意,他希望所有音符的音高 ai 都是 1∼7 的正整数,且相邻的音高差不超过 k 。 现在他要修改若干个音符…

安徽省建设工程造价管理总站网站网站公司名称大全

通过接口实现多态 接口中声明若干个 bstract方法; 方法体的内容细节由实现接口的类去完成,不同的类有 不同的实现方式 → 则接口变量在回调接口方法时具有多 种形态。 用接口进行程序设计的核心思想 使用接口回调技术:接口变量存放实现该接口…

企业门户网站 php制作网页方法

2024年3月25日,马来西亚 - BTM 是领先的投资平台,提出一种全新融合安全性、稳定的方式。BTM 坚守增强投资者信心的承诺,运用前沿科技和由 AI 驱动的算法策略,以及实现快速服务的能力,助力投资者自信地应对市场的不断变…

求网站制作图书翻页的动画 做网站启动用

转载自 Java:关于main方法的10道面试题 1.main方法是做什么用的? 2.不用main方法如何运行一个类? 3.main方法如何传递参数?传递参数的类型是什么?能不能改变该参数类型? 4.main方法为什么是静态的&#xff…

基于工作过程的商务网站建设 网页制作网站开发第三方支付

jQuery事件 jQuery事件是对JavaScript事件的封装,常用事件分类 基础事件 鼠标事件键盘事件window事件表单事件绑定事件与移除事件复合事件 鼠标光标悬停鼠标连续点击jQuery基础事件 鼠标事件 鼠标事件是当用户在文档上移动或单击鼠标时而产生的事件 下面是一个使用 Markdow…

淮安市建设工程安全监督站网站做课件的网站有哪些

Java进阶之旅第三天 文章目录 Java进阶之旅第三天TreeMap特点:题目 使用TreeMap进行数据统计题目: TreeMap 特点: 1.TreeMap根TreeSet底层原理一样,都是红黑树结构2.由键决定特性: 不重复,无索引,可排序3.可排序: 对键进行牌序注意: 默认按照键的从小到大进行排序,也可以自己…

建设银行演示网站电子商务网站建设有哪些流程

答: ● 第一次渲染 ○ html结构 解析为 dom树 ○ css样式 解析为 样式规则 ○ dom树 和 样式规则 匹配下,生成渲染树! ○ 接下来就是重排:根据渲染树,得到每个盒子的几何信息(大小位置) ○ 最后…

徐州网站定制公司郑州买房三大网站

《企业文化建设与管理》模拟题 一单选题 1.组织文化包括 A.物质文化,社会文化,精神文化 B.物质文化,精神文化,政治文化 C.物质文化,行为文化,制度文化 D.物质文化,社会文化,政治文化…

微信公众平台网站开发网站样式用什么做的

来源:199IT互联网数据中心《悬而未决的AI竞赛——全球企业人工智能发展现状》由德勤洞察发布,德勤中国科技、传媒和电信行业编译。为了解全球范围内的企业在应用人工智能技术方面的情况以及所取得的成效,德勤于2018年第三季度针对早期人工智能…

怎么注册自己的网站域名本周新闻热点10条2021

Kotlin语言的数据库编程 引言 Kotlin是一种现代的编程语言,因其简洁、强大和安全性而受到广泛欢迎。自从Google宣布Kotlin成为Android开发的官方语言以来,它的使用范围不断扩大,尤其是在移动应用开发、服务器端开发和数据科学等领域。在本篇…

淘宝网站推广策划方案seo沈阳

单纯靠WebView2是没办法通过JS实现自动登录操作的,包括浏览器插件,都不行,因为大公司对反爬机制控制的还是挺严格。 下面是实现效果,私信我,咨询解决方案。 20231202_153912 C#有偿Q群:927860652博客仅为…

深圳网站建设制作今天重大新闻

1.拼接与拆分 CatStackSplitChunk 2.Cat 有两张成绩单 [class1-4,students,scores] [class5-9,students,scores]’ 要把这两个成绩单合并在一起 如何理解该行为 注意:班级情况中 A的tensor是[4,32,8],B的tensor是[5,32,8]如果我们是在0维上进行拼接,要…

怎么做国外的网站客户资源买卖平台

前言 CVE-2022-23880是一个影响taoCMS v3.0.2的任意文件上传漏洞。攻击者可以利用此漏洞通过上传特制的PHP文件在受影响的系统上执行任意代码。 漏洞细节 描述: 在taoCMS v3.0.2的文件管理模块中存在任意文件上传漏洞。攻击者可以通过上传恶意的PHP文件来执行任意代码。 影响…

seo 网站 制作wordpress调取某页面

大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。 水稻是全球重要的农作物,也是单子叶植物模型。在水稻中,N6-甲基腺苷(m6A)mRNA修饰对植物的发育和胁迫响应至关重要。OsFIP37作为m6A甲基化…

广东专业网站建设公司什么软件做美食视频网站

1、简介 MySQL 和 Redis 如何保证数据一致性,目前大多讨论的是先更新Redis后更新MySQL,还是先更新MySQL 后更新Redis,这两种方式在实际的应用场景中都不能确保数据的完全一致性,在某些情况下会出现问题,本文介绍使用 C…

手机免费建站工具怎么建设英文网站

内部类 1. 认识内部类 它是类中的五大成分之一(成员变量、方法、构造器、内部类、代码块)如果一个类定义在另一个类的内部,这个类就是内部类。 public class Test {public static void main(String[] args) {// 直接输出: 内部类的静态成员…