广告
返回顶部
首页 > 资讯 > 移动开发 >Flow转LiveData数据丢失原理详解
  • 920
分享到

Flow转LiveData数据丢失原理详解

Flow转LiveData数据丢失Flow转LiveData 2023-01-09 09:01:24 920人浏览 泡泡鱼
摘要

目录前言示例总结前言 翻译自:arkadiuszchmura.com/posts/be-ca… 最近我在负责一段代码库,需要在使用 Flow 的 Data 层和仍然依赖

前言

翻译自:arkadiuszchmura.com/posts/be-ca…

最近我在负责一段代码库,需要在使用 Flow 的 Data 层和仍然依赖 LiveData 暴露 State 数据的 UI 层之间实现桥接。好在 Androidx.lifecycle 框架已经提供了一个叫做 asLiveData() 的方法,可以让你毫不费力地将 Flow 转为 LiveData

然而使用这种方式得到的 LiveData 需要牢记一点:在拥有一个及以上活跃的观察者的条件下,它才会发射数据。假使上游的 flow 产生了更新,但对应的 LiveData 并非活跃的状态,那么它将无法获得最新的数值。

让我通过如下的实例,向你展示我们可能会遇到的这种潜在问题。

示例

我们有一个简单的 Activity,它持有 AAC ViewModel 的实例:

 class MainActivity : AppCompatActivity() {  
     private val viewModel: MainViewModel by viewModels()  
   
     override fun onCreate(savedInstanceState: Bundle?) {  
         super.onCreate(savedInstanceState)  
         setContentView(R.layout.activity_main)    
     }  
 }
复制代码

ViewModel 的实现是这样的:

 class MainViewModel : ViewModel() {  
     private val repository = Repository()  
   
     val state: LiveData<Int> = repository.state.asLiveData()  
 }
复制代码

它持有一个 Repository 实例,充当琐碎的数据层。

同时 ViewModel 还通过前面提到的 asLiveData() 方法,将 Repository 持有的 StateFlow 转为了 LiveData 并对外暴露了其 State 数据。

Repository 的实现如下:

 class Repository {  
     private val _state = MutableStateFlow(-1)  
     val state: StateFlow<Int> = _state  
   
     suspend fun update() {  
         _state.emit(Random.nextInt(until = 1000))  
     }  
 }
复制代码

它拥有一个包裹着 Integer 数据(初始值为 -1)的 StateFlow 示例,同时对外提供了一个方法允许外界更新它的 State:从 0 到 1000 之间取得一个新的随机数。

试想一下,假使希望 Activity 创建的时候就能执行这个数据更新。我们可以这么实现:

  • MainViewModel 内创建一个 init() 来做这个操作
  • Activity 的onCreate() 里调用该方法
 // MainViewModel
 fun init() {
     // update() is suspending, so we launch a new coroutine here
     viewModelScope.launch {  
         repository.update()
     }  
 }
 ​
 // MainActivity
 override fun onCreate(savedInstanceState: Bundle?) {  
     super.onCreate(savedInstanceState)  
     setContentView(R.layout.activity_main)  
   
     viewModel.init()
 }
复制代码

这样的话,Activity 创建的时候一个新的协程将被启动,最终会调用 Repository 的 update() ,生成一个随机数并发射到它的 State。

此外,我们可能还需要在 ViewModel 中去发送包含了新生成数值的事件出去。可以在 ViewModel 中添加一个sendAnalyticalEvent() ,这样可以在执行完 Repository 的 update() 之后立即调用它。

 // MainViewModel
 fun init() {  
     viewModelScope.launch {  
         repository.update()  
         sendAnalyticalEvent() // <-- NEW
     }  
 }  
   
 private fun sendAnalyticalEvent() {  
     // Typically, we would schedule a network request here  
   
     val liveDataValue = state.value  
     val flowValue = repository.state.value  
     Log.d("Current number in LiveData", "$liveDataValue")  
     Log.d("Current number in StateFlow", "$flowValue")  
 }
复制代码

该方法内,我们可以做些典型的操作,比如向后端服务器发送网络请求。这里,让我们仅仅在 LoGCat 里打印来自 LiveData and Flow 的数值即可。

1.png

上面的运行结果相当出乎意料。你可能会争辩道:LiveData 没有获取到最新的数值,是因为没有足够的时间从上游的 flow 中收集数据,不然的话肯定能够拿到正确的数值。

但这个 case 里,不仅仅是 LiveData 获得到的是错误的数值,它获得到的是 null。而且请别忘了,它的存放在 Repository 里的初值是 -1。这只能代表一个意思:这里的 LiveData 压根没有从 StateFlow 里收集任何数据。

原因是我们还没有开始观察这个 LiveData,它自然会被当作是非活跃的。而且根据 asLiveData() 方法的文档可以知道,在这种情况下 LiveData 不会从上游的 flow 收集任何数据。

asLiveData:Creates a LiveData that has values collected from the origin Flow.

上游 flow 数据的收集发生在 LiveData 变成活跃的时候,即 LiveData.onActive。如果 flow 尚未完成,而 LiveData 变成了非激活状态,即 LiveData.onActive,那么 flow 的数据收集将在timeoutInMs 参数指定的时间后被取消。除非在超时之前,LiveData 变成活跃状态。

一旦我们开始在 Activity 里观察 LiveData 的数据(因此将促使 LiveData 变成活跃状态),它就能够拥有正确的、最新的数值了。

 // MainActivity
 override fun onCreate(savedInstanceState: Bundle?) {  
     super.onCreate(savedInstanceState)  
     setContentView(R.layout.activity_main)  
   
     viewModel.init()  
     viewModel.state.observe(this) { // <-- NEW  
         Log.d("Current number in MainActivity", "$it")  
     }  
 }
复制代码

如下是 Logcat 里新的输出。

2.png

上面的示例里,我们采用的是 StateFlow,但规则同样适用于 SharedFlow

而且,情况将更加糟糕,因为当 LiveData 处于非激活状态的时候,任何发送给 SharedFlow 的事件都将永久丢失(默认情况下 SharedFlow 不会将任何数值重新发送给新的订阅者)。

总结

请时刻记住采用 asLiveData() 方法转换 Flow 得到的 LiveData 将会和预期的稍稍不同:它只会在注册了活跃观察者的情况下发射数据

就我个人而言,这种行为无可厚非:因为我们都还没有观察它、自然不会在意 LiveData 的数值是啥、能不能获取得到。但话说回来,确实存在一些场景,需要在你尚未开始观察的时候,去访问 ViewModelLiveData 的当前数值。

通过阅读这篇文章,我希望你在遇到这种获取不到正确数值的情况时,不要惊讶、心中有数。

以上就是Flow转LiveData数据丢失原理详解的详细内容,更多关于Flow转LiveData数据丢了的资料请关注编程网其它相关文章!

--结束END--

本文标题: Flow转LiveData数据丢失原理详解

本文链接: https://www.lsjlt.com/news/177117.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Flow转LiveData数据丢失原理详解
    目录前言示例总结前言 翻译自:arkadiuszchmura.com/posts/be-ca… 最近我在负责一段代码库,需要在使用 Flow 的 Data 层和仍然依赖...
    99+
    2023-01-09
    Flow转LiveData数据丢失 Flow转LiveData
  • MySQL 丢失数据的原因及解决
    前言 最近偶尔会收到用户反馈数据不见了,数据丢失了的问题。从现象上来看,这类问题在数据库层面就是紧急程度最高的那一类了,抛开客观条件来说,针对这一类问题的恢复手段几乎只有备份恢复+回放 Binlog,耗时一般比较久...
    99+
    2022-05-12
    MySQL 丢失数据 MySQL 丢失数据解决
  • 详解win7升级win10数据会丢失吗
    微软已经停止了对win7系统的更新和支持,很多网友为了电脑系统安全想要将win7升级win10,但是不知道win7升级win10数据会丢失吗?如何保存win7系统数据?下面小编就跟大家聊聊win7升级win10数据是否会丢失。详细如下:1、...
    99+
    2023-07-16
  • mongodb数据丢失的原因及解决方法是什么
    MongoDB数据丢失的原因可能有多种,包括硬件故障、网络故障、软件错误、人为操作错误等。以下是一些常见的原因和解决方法: 硬件...
    99+
    2023-10-21
    mongodb
  • MySQL数据丢失的原因是什么及怎么解决
    这篇文章主要介绍了MySQL数据丢失的原因是什么及怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇MySQL数据丢失的原因是什么及怎么解决文章都会有所收获,下面我们一起来...
    99+
    2023-04-28
    mysql
  • SpringBoot2.0解决Long型数据转换成json格式时丢失精度问题
    目录解决Long型数据转换成json格式时丢失精度SpringBoot时间格式,Long型精度丢失常见问题时间格式,Long型精度丢失解决Long型数据转换成json格式时丢失精度 ...
    99+
    2022-11-13
  • 代理服务器购买使用数据丢失如何解决
    代理服务器购买使用数据丢失的解决方法:1、如果是误删除或格式化,可以在网上下载恢复软件来恢复数据;2、如果是服务器数据丢失,不要盲目操作,先关机停止硬盘读写数据,然后寻找正规的数据恢复公司或请专业技术人员检查;3、如果是机房的硬件损坏,则需...
    99+
    2022-10-24
  • 阿里云服务器接收数据丢失原因、影响及解决方案
    在互联网应用中,服务器接收数据是必不可少的环节。然而,由于各种原因,阿里云服务器可能会出现接收数据丢失的情况,这不仅可能影响用户的使用体验,也可能导致数据丢失或损坏。本文将详细介绍阿里云服务器接收数据丢失的原因、影响以及解决方案。 原因:硬...
    99+
    2023-10-31
    阿里 数据丢失 解决方案
  • 详解pandas中缺失数据处理的函数
    目录一、缺失值类型1、np.nan2、None3、NA标量二、缺失值判断1、对整个dataframe判断缺失2、对某个列判断缺失三、缺失值统计1、列缺失2、行缺失3、缺失率四、缺失值...
    99+
    2022-11-13
  • Mysql数据库group by原理详解
    目录引言1. 使用group by的简单例子2. group by 原理分析2.1 explain 分析2.2 group by 的简单执行流程3. where 和 having的区别3.1 grou...
    99+
    2022-07-06
    Mysql数据库group by group by
  • Vue监视数据的原理详解
    目录1. Vue监视数据的原理(set方法)1.1 Vue监视不同类型数据的原理1.1.1 如何监测对象中的数据?1.1.2 如何监测数组中的数据?1.1.3 小案例1.1.4 se...
    99+
    2022-11-13
  • Mysql数据库group by原理详解
    目录引言1. 使用group by的简单例子2. group by 原理分析2.1 explain 分析2.2 group by 的简单执行流程3. where 和 hav...
    99+
    2022-11-13
  • Vue监听数据的原理详解
    目录一、引入二、监测对象  2.1 为什么需要监测对象 2.2数据代理2.3 对象监测相关API之Vue.set2.4 为对象赋多个新值三、监...
    99+
    2022-11-12
  • SpringBoot怎么解决Long型数据转换成json格式时丢失精度问题
    这篇“SpringBoot怎么解决Long型数据转换成json格式时丢失精度问题”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇...
    99+
    2023-07-02
  • 详解Redis数据类型实现原理
    目录1. 对象的类型与编码① type属性② encoding 属性和 *prt 指针2. 字符串对象① 编码② 编码的转换3. 列表对象① 编码② 编码转换4. 哈希对象① 编码②...
    99+
    2022-11-12
  • Vue之监听数据的原理详解
    <body> <div id="root"> <h1>学生的基本信息</h1> <b...
    99+
    2022-11-12
  • 详解vue数据响应式原理之数组
    目录src/core/observer/index.jssrc/core/observer/array.js arrayMethods总结src/core/observer/inde...
    99+
    2022-11-13
  • 阿里云数据库的计数原理详解
    阿里云数据库是阿里巴巴集团自主研发的一种分布式数据库,其主要应用于互联网的大数据处理。在阿里云数据库中,计数原理是十分重要的一个概念,本文将深入探讨阿里云数据库的计数原理。 阿里云数据库的计数原理主要是基于B树和哈希表的结合使用。在阿里云数...
    99+
    2023-10-29
    阿里 详解 原理
  • 阿里云数据库使用原理详解
    阿里云数据库是阿里云推出的一款高性能、高可用的云数据库服务,其主要原理是通过分布式计算、大数据技术、机器学习等手段,实现了数据库的高可用、高性能、高安全性。本篇文章将详细介绍阿里云数据库的使用原理,包括数据存储、数据处理、数据备份和恢复、安...
    99+
    2023-10-28
    阿里 详解 原理
  • mysql数据库查询缓存原理详解
    这篇文章将为大家详细讲解有关mysql数据库查询缓存原理详解,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。mysql数据库查询缓存原理是:1、缓存SELECT操作...
    99+
    2022-10-18
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作