沉思篇-剖析Jetpack的ViewModel

这篇具有很好参考价值的文章主要介绍了沉思篇-剖析Jetpack的ViewModel。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

ViewModel做为架构组件的三元老之一,是实现MVVM的有力武器。

ViewModel的设计目标

ViewModel的基本功能就是管理UI的数据。其实,从职责上来说,这又是对Activity和Fragment的一次功能拆分。以前存储在它们内部的数据,需要它们自己处理创建,更新,存储,恢复的所有过程,同时它们还要处理UI的数据绑定,更新,动画等操作。职责的多元化就容易出现不好定位和调试的问题。另外,Activity和Fragment作为UI的承载者,很多时候需要共享数据和复用功能。而UI的差异让复用的粒度划分很难把控,容易写出扩展性差的代码。基于这些痛点,ViewModel被设计出来了。
同时ViewModel还将保存数据的功能强化了——它将设备配置变更后数据保存和恢复自动化了,在UI生命周期内都能保证数据的有效性,这大大减少了样板代码的编写,提高了开发效率。

ViewModel的架构设计

ViewModel用了两种粒度划分来完成数据管理功能。 第一层是对ViewModel自身存储数据的管理。目标就是完成ViewModel的创建,对应的抽象实体是ViewModelProvider.Factory。第二层则是对已存在的ViewModel组的管理,目标就是保证意外情况下ViewModel的有效性,对应的抽象实体是ViewModelStore。当然,这些都只是概念上的抽象,还需要一个粘合剂把它们的抽象层级体现出来,这就是ViewModelProvider。这三个主体类共同搭建了ViewModel的体系框架。剩下的类都是对这三个概念的补充和完善。接下来我将分别以这些抽象为主线,逐层分析它们的实现逻辑。

ViewModel的组管理

前面也提到过,ViewModelStore是完成组管理的,那么我们首先应该确定的是组的概念,也就是这些ViewModel都归属于谁的问题。这不难理解,要管理组,那就必须得找到组的主人啊,由此引申出了ViewModelStoreOwner,它代表着某个拥有组管理权限的对象,通过它提供的ViewModelStore对象就能对里面的ViewModel进行管理了,同时这些ViewModel也就共同形成了组。所以ViewModelStoreOwner其实就是组的抽象实体,它代表着某个组,也是管理分组的单位。
ViewModel有两个默认实现的组——ComponentActivity和Fragment。也就是说ComponentActivity和Fragment都实现了ViewModelStoreOwner这个接口。
先来看ComponentActivity的实现。根据接口,首先查看接口方法getViewModelStore的实现。里面主要涉及到两个对象,一个就是ViewModelStore的引用mViewModelStore,另一个就很有意思了,它是一个NonConfigurationInstances对象,这是一个简单类,就是保存ViewModelStore对象的。那么它特殊在什么地方呢?它是onRetainNonConfigurationInstance方法的返回对象。

插一个课外知识科普,onRetainNonConfigurationInstance是Activity的一个方法,这个方法是设备配置发生变化(如横竖屏切换的时候)时被系统自动调用的,用于用户保存数据。只要这个方法返回的对象,在设备配置放生改变时都不会被销毁。稍后在重建完成后,可以通过getLastNonConfigurationInstance方法获取到。

接着回到getViewModelStore的实现,刚才说到NonConfigurationInstances对象,它是通过调用getLastNonConfigurationInstance方法获得的。如果方法返回了有效的对象,说明Activity被重建了,就直接获取保存在NonConfigurationInstances对象中的值,然后更新mViewModelStore。否则就说明还没有有效的ViewModelStore对象,则直接创建。从这个逻辑不难看出,我们的ViewModel不会随着设备变化而重建,这正好满足了我们的设计目标。那么对于Fragment,它的实现又是怎样的呢。
Fragment的实现比较曲折,它直接委托给了FragmentManager,又委托给了FragmentManagerViewModel的getViewModelStore方法,方法实现也很简单,就是对HashMap查找,没有就创建新的。这显然不是我们想看到的,因为这里并没有和Activity类似的处理状态变更的逻辑。那么唯一的突破点就是那个HashMap对象了。搜索一圈发现,它会作为getSnapshot方法的返回值返回,有点Activity那味了。往上回溯,会发现它最终就是作为不销毁的对象,在Fragment销毁前保存下来了。
以上就是两种应用场景下ViewModelStore的创建逻辑,另外,还有清除逻辑没有讲到。这个逻辑本质上就是调用ViewModelStore的clear方法,唯一的问题就是确定调用时机。具体来说就是,Activity通过注册Lifecycle的状态监听,在Lifecycle.Event.ON_DESTROY的时候,调用了clear方法,而Fragment则是继续通过FragmentManager的desctory方法作为调用的入口点。在FragmentManagerViewModel里完成了方法调用。
总结一下,ViewModelStoreOwner是对ViewModel组的一种抽象。虽然对应着两个不同的实现,但是殊途同归,最终的目的就是保证在设备配置发生变化的时候对应ViewModelStore对象的有效性, 从而保证ViewModel对象的有效性。同时在真正需要销毁的时候做好清理工作。这就是这ViewModel的组管理功能。

ViewModel的创建管理

ViewModel用ViewModelProvider.Factory来管理创建过程。具体来说就是怎样根据一个ViewModel子类的类信息创建对应的对象。这有两个难点——必要的依赖注入、数据的恢复。对于依赖注入,ViewModel还是耍了老把戏,和创建ViewModelStore类似,提供了HasDefaultViewModelProviderFactory的一个抽象,把依赖注入转移到了ComponentActivity和Fragment中。之所以这么做,是因为在创建ViewModel的过程中,可能需要使用到Application和Bundle等信息,而这些信息是只能在在Activity和Fragment中才能获取到的。数据恢复则是关注怎样利用现有的数据将对象恢复到原来的状态。当然这些过程其实都可以没有,不需要传递Application或者Bundle对象,不需要恢复ViewModel状态,则库提供了默认的实现。就是简单的调用反射创建对象而已。
针对刚才说的各种情况,ViewModelProvider.Factory有多个实现,那么实际上它到底是使用哪个实现呢,我们得从ViewModelProvider中寻找答案。在它的构造方法里,会对ViewModelStoreOwner做类型判断,假如它是HasDefaultViewModelProviderFactory的实例,则使用实例返回的对象,否则默认的实现。结合上面的分析,让我们继续到ComponentActivity和Fragment中寻找答案。不看不知道,一看吓一跳,它们竟然都是使用了SavedStateViewModelFactory类,那么我们一起来看看它是怎么实现的吧。
在构建SavedStateViewModelFactory对象的时候,会传入三个对象——Application,SavedStateRegistryOwner,Bundle,这三个对象中最重要的就是第二个,它的主要功能就是提供在SavedStateRegistry对象,这个对象会在合适的时候保存数据,然后在合适的时候再恢复过来。它也是生命周期感知的组件。在它的create方法里,也是通过反射构建ViewModel对象的,唯一的不同就是反射多了个参数。接着往下看,最终会利用这些信息构造出SavedStateHandle对象,这个对象就是真正对我们当前创建的ViewModel对象有用的信息。SavedStateHandle提供了根据键值对保存数据的方法,也提供了查询方法,所以ViewModel可以根据这个对象,恢复自己的LiveData数据,最重要的,这个类还提供了LiveData的另一个子类SavingStateLiveData,能自动处理数据保存的问题。
一句话总结,ComponentActivity和Fragment会使用SavedStateViewModelFactory对象作为ViewModelProvider中的Factory来创建ViewModel。只要ViewModel提供了带有Application或者SavedStateHandle的构造方法,就能享受从Bundle中恢复数据的便利。

ViewModel的粘合剂ViewModelProvider

为什么说ViewModelProvider是粘合剂呢?因为这个类就做了一件事,把ViewModelStore和ViewModelProvider.Factory组合起来,实现了一个叫get的方法,这个方法的内部实现就是有两个步骤。

  1. 调用ViewModelStore的get方法查询是否有创建好的对象,如果有就返回,方法结束,否则进入步骤2。

  2. 调用ViewModelProvider.Factorycreate方法创建对象,并将之保存到ViewModelStore中。

所以当我们要使用ViewModel的时候,通常是创建ViewModelProvider对象,然后调用get方法获取真正的ViewModel对象,这样,我们的对象就具备了正确处理设备配置变更的能力。

ViewModel的Fragment间通信功能

根据前面的梳理,我们知道,ViewModelStore是管理某个ViewModel组的,只要我们保证ViewModelStore存在,我们就可以保证ViewModel存活。再反推一步,要保证ViewModelStore存活,我们就要保证ViewModelStoreOwner在不同的地方都能返回同一个ViewModelStore对象,而ComponentActivity和Fragment是都实现了这个接口的。结合Activity的生命周期通常是大于Fragment这一事实,不难得出结论——在某个Fragment里面,用Activity对象创建ViewModelProvider对象,就能保证获取到和Activity一样的ViewModelStore对象,也就能保证获取到相同的ViewModel对象。只要Activity没有销毁,该Activity下的所有Fragment都能获取到相同的ViewModel对象,然后通过更改状态能方式完成通信。

到此,对ViewModel的分析告一段落了,对创建过程的两次抽象是我觉得最精彩的环节,另外对现有条件(Activity和Fragment的生命周期)的利用也是它独到之处,真的是受益匪浅。青山不改,绿水长流,咱们下期见!
沉思篇-剖析Jetpack的ViewModel文章来源地址https://www.toymoban.com/news/detail-481276.html

到了这里,关于沉思篇-剖析Jetpack的ViewModel的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 王学岗码牛jetpack系列之ViewModel

    ViewModel的目的:存储数据,以注重生命周期的方式管理界面的相关数据 viewModel的特性:1,数据持久化,不依赖于Activity的生命周期,有自己独立的生命周期 2,异步回调不会造成内存泄漏 3,隔离Model层与View层 4,Fragments间共享数据 我们看一段代码 看下打印结果 Activity不一样了,

    2024年02月02日
    浏览(43)
  • Android Jetpack 从使用到源码深耕【ViewModel从实践到原理 】(二)

    上文,我们对ViewModel的引入背景、使用、进行了实例编码、总结分析,本文开始,我们对ViewModel的实现源码,进行探索、总结。 Android Jetpack 从使用到源码深耕【ViewModel从实践到原理 】(一) Android Jetpack 从使用到源码深耕【ViewModel从实践到原理 】(二) Android Jetpack 从使用

    2024年02月04日
    浏览(39)
  • Android Jetpack 从使用到源码深耕【ViewModel从实践到原理 】(一)

    五一期间,我们来一起学习总结一下Jetpack的ViewModel组件,从使用、源码、经验来总结分析。 Android Jetpack 从使用到源码深耕【ViewModel从实践到原理 】(一) Android Jetpack 从使用到源码深耕【ViewModel从实践到原理 】(二) Android Jetpack 从使用到源码深耕【ViewModel从实践到原理

    2024年02月01日
    浏览(38)
  • Android Jetpack 从使用到源码深耕【ViewModel从实践到原理 】(三)

    上文,我们通过简单的ViewModel使用源码入手,对其源码进行阅读,原理进行了简单总结,简单来说,ViewModel是通过Activity的onRetainNonConfigurationInstance 与 getLastNonConfigurationInstance的自动调用,实现了 ViewModel数据的存储和恢复,数据存储在ViewModelStore的map中,更加明确的话,应该是

    2024年02月04日
    浏览(99)
  • 【Jetpack】ViewModel + LiveData + DataBinding 综合使用 ( 核心要点说明 | 组合方式 | 代码示例 )

    ViewModel 架构组件 是 视图 View 与 数据模型 Model 之间 数据交互的 桥梁 ; 传统 Android 开发中 , 视图 View 与 数据模型 Model 都在 Activity 中维护 , 导致 二者有很高的耦合度 , 不利于代码维护 ; 引入了 ViewModel 架构组件后 , 视图 View 与 数据模型 Model 之间实现了解耦 , 同时也能 保证二

    2024年02月01日
    浏览(35)
  • 【Jetpack】Room + ViewModel + LiveData 综合使用 ( 核心要点说明 | 组合方式 | 代码示例 )

    在上一篇博客 【Jetpack】使用 Room 框架访问 Android 平台 SQLite 数据库 ( 导入依赖 | 定义 Entity 实体类 | 定义 Dao 数据库访问对象接口 | 定义数据库实例类 ) 中 , 实现了 使用 Room 框架访问 Android 中的 SQLite 数据库的操作 , 每当数据库中的数据发生变化时 , 就需要开启线程 , 重新获

    2024年02月06日
    浏览(30)
  • 【Jetpack】Jetpack 简介 ( 官方架构设计标准 | Jetpack 组成套件 | Jetpack架构 | Jetpack 的存在意义 | AndroidX 与 Jetpack 的关系 )

    Android 架构发展 : Android 架构的发展 途径了 MVC - MVP - MVVM 等方案 , 这些架构都 不是 Google 官方提出的 , 都是各个团队 根据自己的需求推出的适合自己的架构方案 ; Jetpack 是 Google 推出的 架构设计标准 , 是官方推出 架构设计指导方案 ; 借助 Jetpack 提供的一系列的 工具 和 组件

    2024年02月03日
    浏览(30)
  • Jetpack Compose UI架构

    Jetpack Compose是我职业生涯中最激动人心的事。它改变了我工作和问题思考的方式,引入了易用且灵活的工具,几乎可轻松实现各种功能。 早期在生产项目中尝试了Jetpack Compose后,我迅速着迷。尽管我已有使用Compose创建UI的经验,但对新的Jetpack Compose驱动特性的组织和架构引发

    2024年02月11日
    浏览(37)
  • 【Jetpack】DataBinding 架构组件 ⑥ ( RecyclerView 数据绑定 )

    在 RecyclerView 中 , 如果要使用 DataBinding 架构组件进行数据绑定 , 首先要 启用 DataBinding , 并 导入 RecyclerView 依赖 , 在 Module 模块下的 build.gradle 构建脚本 中 , 配置如下内容 : 要绑定的数据是 RecyclerView 条目的数据 , 因此需要 将条目布局设置为 DataBinding 布局 ; 创建 item.xml 布局后

    2023年04月25日
    浏览(33)
  • 【见微知著】Android Jetpack - Navigation的架构设计

    前言:人总是理所当然的忘记,是谁风里雨里,一直默默的守护在原地。 Navigation 作为 Android Jetpack 组件库中的一员,是一个通用的页面导航框架。为 单 Activity 架构而生的端内路由导航,用来管理 Fragment 的切换,并且可以通过可视化的方式,看见 App 的交互流程。今天主要来

    2024年02月08日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包