| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> ViewModel-Flow-LiveData,我们还是好朋友 -> 正文阅读 |
|
[移动开发]ViewModel-Flow-LiveData,我们还是好朋友 |
点击上方蓝字关注我,知识会给你力量 在Android应用程序中加载UI数据可能是一个挑战。各种屏幕的生命周期需要被考虑在内,还有配置的变化导致Activity的破坏和重新创建。 当用户在一个应用程序中进一步或后退,从一个应用程序切换到另一个应用程序,或者设备屏幕被锁定或解锁时,应用程序的各个屏幕会在互动和隐藏之间不断切换。每个组件都需要公平竞争,只有在给了资源的情况下才执行积极的工作。 配置变化发生在不同的场合:当改变设备方向、将应用程序切换到多窗口模式或调整其窗口大小、切换到黑暗或光明模式、改变默认区域或字体大小等等。 Goals of efficiency为了在Activities和Fragments中实现高效的数据加载,从而获得最佳的用户体验,应该考虑以下几点。
Today: ViewModel and LiveData为了帮助开发者以可管理的复杂度的代码实现这些目标,谷歌在2017年以ViewModel和LiveData的形式发布了第一个架构组件库。这是在Kotlin被引入为开发Android应用程序的推荐编程语言之前。 ViewModel是跨越配置变化而保留的对象。它们对于实现目标#1和#3很有用:在配置变化期间,加载操作可以不间断地在其中运行,而产生的数据可以缓存在其中,并与当前连接到它的一个或多个Fragment/Activity共享。 LiveData是一个简单的可观察数据持有者类,也是生命周期感知的。只有当观察者的生命周期至少处于STARTED(可见)状态时,新的值才会被派发给观察者,而且观察者会自动取消注册,这对于避免内存泄漏很方便。LiveData对于实现目标#1和#2很有用:它缓存了它所持有的数据的最新值,并且该值会自动派发给新的观察者。另外,当在STARTED状态下没有更多的注册观察者时,它会得到通知,这可以避免执行不必要的后台工作。 ? LiveData + Coroutines与RxJava等反应式流解决方案相比,LiveData本身是相当有限的。
为了帮助克服这些限制,Jetpack库还提供了从LiveData到其他技术的桥梁,如RxJava或Kotlin的coroutines。 在我看来,最简单、最优雅的桥梁是androidx.lifecycle:lifecycle-livedata-ktx Gradle依赖项提供的LiveData coroutine builder函数。这个函数类似于Kotlin Coroutines库中的flow {} builder函数,可以将一个coroutine巧妙地包装成一个LiveData实例。
? 如果资源库提供了以Flow形式返回数值流的函数,而不是暂停返回单一数值的函数,那该怎么办?也可以通过使用asLiveData()扩展函数将其转换为LiveData并利用上述所有特性。
在SDK里,asLiveData()还使用了LiveData coroutines builder来创建一个简单的coroutine,在LiveData处于活动状态时对Flow进行collect操作。
但是,让我们暂停一下--究竟什么是Flow,是否可以用它来完全替代LiveData? Introducing Kotlin’s FlowFlow是Kotlin的Coroutines库在2019年推出的一个类,它代表了一个异步计算的数据流。它的概念类似于RxJava的Observables,但基于coroutines,有一个更简单的API。 起初,只有冷流可用——无状态的流,每次观察者开始在coroutine的范围内collect他们的值时,都会按需创建。每个观察者得到它自己的值序列,它们不被共享。 后来,新的热流子类型SharedFlow和StateFlow被添加,并在Coroutines库的1.4.0版本中作为稳定的API毕业。 SharedFlow允许发布被广播给所有观察者的值。它可以管理一个可选的重放缓存和/或缓冲区,并且基本上取代了所有被废弃的BroadcastChannel API。 StateFlow是SharedFlow的一个专门和优化的子类,它只存储和重放最新的值。听起来很熟悉? StateFlow和LiveData有很多共同点。
但是它们也有重要的区别。
Observing LiveData vs Collecting Flow从Fragment的一个Activity中观察一个LiveData实例是很直接的。
这是一个一次性的操作,LiveData负责将流与观察者的生命周期同步起来。 对于Flow来说,相应的操作被称为collect,collect需要通过一个协程来完成。因为Flow本身不具有生命周期意识,所以与生命周期同步的责任被转移到collectFlow的coroutine上。 要创建一个生命周期感知的coroutine,在一个Activity/Fragment处于STARTED状态时collect一个Flow,并在Activity/Fragment被销毁时自动取消collect,可以使用以下代码。
但是这段代码有一个主要的限制:它只能在没有通道或缓冲区支持的冷流中正常工作。这样的流只由collect它的coroutine驱动:当Activity/Fragment移动到STOPPED状态时,coroutine将暂停,Flow producer也将暂停,在coroutine恢复之前不会发生其他事情。 然而,还有其他类型的流。
对于这些情况,即使Flow collect的coroutine被暂停,底层的Flow生产者也会保持活跃,在后台缓冲新的结果。资源被浪费了,目标#2被错过了。 需要实现一种更安全的方式来collect任何类型的流。当Activity/Fragment变得不可见时,执行collect的coroutine必须被取消,并在它再次变得可见时重新启动,这与LiveData coroutine builder的做法完全一样。为此,在lifecycle:lifecycle-runtime-ktx:2.4.0中引入了新的API(在写这篇文章时仍处于alpha状态)。
或者说是。
正如你所看到的,为了达到同样的安全和效率水平,用LiveData观察Activity或Fragment的结果更简单。 你可以在Manuel Vivo的文章《以更安全的方式从Android UIscollect流量》中了解更多关于这些新的API。 Replacing LiveData with StateFlow in ViewModels让我们回到ViewModel。我们确立了这是一种使用LiveData异步获取数据的简单而有效的方法。
我们怎样才能用StateFlow代替LiveData达到同样的效果?Jose Alcérreca写了一个很长的迁移指南来帮助回答这个问题。长话短说,对于上述用例,等效的代码是。
stateIn()操作符将我们的冷流转换为热流,能够在多个观察者之间共享一个结果。由于SharingStarted.WhileSubscribed(5000L)的存在,热流在第一个观察者订阅时被懒散地启动,并在最后一个观察者退订后5秒被取消,这样可以避免在后台做不必要的工作,同时也考虑到了配置变化。此外,一旦上游流到达终点,它就不会被共享的coroutine自动重启,所以我们避免做两次相同的工作。 看起来我们成功地实现了我们的3个目标,并使用更复杂一点的代码复制了几乎与LiveData相同的行为。 但是仍然有一个小的关键区别:每次一个Activity/Fragment再次变得可见时,一个新的流集合将开始,StateFlow总是通过立即向观察者提供最新的结果来启动流。即使这个结果在之前的集合中已经被传递给了同一个Activity/Fragment。因为与LiveData不同,StateFlow不支持版本控制,每一个流程集合都被认为是一个全新的观察者。 这有问题吗?对于这个简单的用例,并没有:一个Activity或Fragment可以只是执行一个额外的检查,以避免更新视图,如果数据没有改变。
但在更复杂的、真实的使用案例中可能会出现问题,我们将在下一节看到。 Using StateFlow as trigger in a ViewModel一个常见的情况是使用基于触发器的方法在ViewModel中加载数据:每次触发器的值被更新时,数据就会被刷新。使用MutableLiveData,效果非常好。
这段代码足够简单,并且达到了所有效率的目标。 现在让我们看看是否可以用MutableStateFlow代替MutableLiveData来实现同样的逻辑。 天真的方法:
MutableLiveData和MutableStateFlow的API非常接近,触发代码看起来几乎相同。最大的区别是mapLatest()转换函数的使用,对于单个返回值,它相当于LiveData的switchMap()(对于多个返回值,应该使用flatMapLatest())。 mapLatest()的工作原理与map()类似,但不是依次对所有输入值完全执行转换,而是立即消耗输入值,在一个单独的coroutine中异步执行转换。当一个新的值在上游流程中发出时,如果之前的值的转换循环程序仍在运行,它将被立即取消,一个新的循环程序将被启动以取代它。这样一来,就可以避免在过时的值上工作。 到目前为止还不错。然而,这段代码的主要问题来了:因为StateFlow不支持版本控制,当流程集合重新启动时,触发器将重新发送最新的值。每当Activity/Fragment在不可见超过5秒后再次变得可见时就会发生这种情况。 而当触发器再次发出相同的值时,mapLatest()转换将再次运行,用相同的参数再次冲击存储库,尽管结果已经被传递和缓存了! 目标1被错过了:仍然有效的数据不应该被第二次加载。 Preventing re-emission of the latest trigger value接下来想到的问题是:我们是否应该防止这种重新加载,以及如何防止?StateFlow已经处理了从流程集合中扣除值的问题,而distinctUntilChanged()操作符对其他类型的流程也做了同样的处理。但是没有标准的操作符来重复同一流程的多个集合的值,因为流程集合应该是独立的。这是与LiveData的一个主要区别。 在使用stateIn()操作符的多个观察者之间共享Flow的特定情况下,发射的值将被缓存,并且在任何给定的时间,最多只有一个collect源Flow的coroutine。看起来很有诱惑力的是,黑掉一些运算符函数,这些运算符函数会记住以前collect的最新值,以便在新的collect开始时能够跳过它。
? 不幸的是,上面的逻辑是有缺陷的,当下游的流转换在完成之前被取消时,将不能按预期的那样工作。 代码假设在emit(value)返回后,该值已经被处理,如果流程集合重新开始,就不应该再被发射,但这只有在使用无缓冲的Flow操作符时才是真的。像mapLatest()这样的操作符是有缓冲的,在这种情况下,emit(value)会立即返回,而转换是异步执行的。这意味着没有办法知道一个值何时被下游的流完全处理。如果流collect在异步转换的中间被取消,我们仍然需要在流collect重新启动时重新发射最新的值,以便恢复该转换,否则该值将丢失。 ? 这就是为什么在ViewModel中使用LiveData作为触发器时,LiveData要优于StateFlow,尽管在Google的 "Advanced coroutines with Kotlin Flow "代码实验室中没有提到这些差异,这意味着Flow的实现方式与LiveData的实现方式完全相同。事实并非如此。 Conclusion以下是我基于上述演示的建议。
现在你知道了,如果你还想完全 "随波逐流",将LiveData从你的Android UI层中铲除,你愿意做哪些取舍了。 原文翻译自:https://bladecoder.medium.com/kotlins-flow-in-viewmodels-it-s-complicated-556b472e281a 向大家推荐下我的网站?https://xuyisheng.top/??点击原文一键直达 专注 Android-Kotlin-Flutter 欢迎大家访问 往期推荐 本文原创公众号:群英传,授权转载请联系微信(Tomcat_xu),授权后,请在原创发表24小时后转载。 < END > 作者:徐宜生 更文不易,点个“三连”支持一下👇 |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 1:18:00- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |