【问题标题】:Kotlin Flow vs LiveDataKotlin Flow 与 LiveData
【发布时间】:2020-03-12 09:05:43
【问题描述】:

在上一次 Google I/O 中,Jose Alcerreca 和 Yigit Boyar told us 认为我们不应再使用 LiveData 来获取数据。现在我们应该使用暂停函数进行一次性获取,并使用 Kotlin 的 Flow 创建数据流。我同意协程非常适合一次性获取或其他 CRUD 操作,例如插入等。但是在我需要数据流的情况下,我不明白 Flow 给了我什么优势。在我看来,LiveData 也在做同样的事情。

流程示例:

视图模型

val items = repository.fetchItems().asLiveData()

存储库

fun fetchItems() = itemDao.getItems()

@Query("SELECT * FROM item")
fun getItems(): Flow<List<Item>>

LiveData 示例:

视图模型

val items = repository.fetchItems()

存储库

fun fetchItems() = itemDao.getItems()

@Query("SELECT * FROM item")
fun getItems(): LiveData<List<Item>>

我还希望看到一些使用协程和 Flow 与 Room 或 Retrofit 配合使用的项目示例。我发现只有一个谷歌的ToDo sample,其中协程用于一次性获取,然后在更改时手动重新获取数据。

【问题讨论】:

    标签: android kotlin android-livedata kotlin-coroutines kotlinx.coroutines.flow


    【解决方案1】:

    Flow 有点像 reactive stream (如 rxjava )。有很多不同的运算符,例如.mapbuffer()(无论如何都更少。与 rxJava 相比的运算符)。因此,LiveDataFlow 之间的主要区别之一是您可以使用在其他线程中订阅地图 computation / transformation

     flowOn(Dispatcher....). 
    

    所以,例如:-

     flowOf("A","B","C").map { compute(it) }.flowOn(Dispatchers.IO).collect {...} // U can change the execution thread of the computation ( by default its in the same dispatcher as collect )
    

    LiveDatamap,以上不能直接实现!

    因此建议在存储库级别保持流量,并使实时数据成为 UI 和存储库之间的桥梁!

    主要区别在于

    • 一般来说,一个普通的flow知道生命周期,但liveData知道生命周期。 (我们可以将 stateFlow 与 repeatOnLifecycle 结合使用,使其具有生命周期意识)
    • flow 有很多不同的运算符,而 livedata 没有!

    但同样,这取决于你如何构建你的项目!

    【讨论】:

    • 需要注意的是,协程现在有 StateFlow 类。这个类与 LiveData 类非常相似,因为可以直接从任何上下文访问值,并且任何更改都会自动发送给任何观察者。但是因为它是一个 Flow 对象,这意味着所有好的协程运算符都可用。
    【解决方案2】:

    顾名思义,您可以将 Flow 视为多个异步计算值的连续流。从我的角度来看,LiveData 和 Flow 之间的主要区别在于 Flow 不断地发出结果,而 LiveData 将在获取所有数据时更新并立即返回所有值。在您的示例中,您正在获取单个值,这与 Flow 的设计目的不完全相同 [更新:为此使用 StateFlow]。

    我没有 Room 示例,但假设您正在渲染需要时间的东西,但您想在渲染和缓冲下一个结果时显示结果。

    private fun render(stuffToPlay: List<Any>): Flow<Sample> = flow {
         val sample = Sample()
         // computationally intensive operation on stuffToPlay
         Thread.sleep(2000)
         emit(sample)
    }
    

    然后,在您的“播放”功能中,您可以显示结果,其中 stuffToPlay 是要渲染的对象列表,例如:

    playbackJob = GlobalScope.launch(Dispatchers.Default) {
                
        render(stuffToPlay)
            .buffer(1000)   // tells the Flow how many values should be calculated in advance
                
            .onCompletion {
                // gets called when all stuff got played
            }
            .collect{sample ->
               // collect the next value in the buffered queue
               // e.g. display sample
            }
    }
    

    Flow 的一个重要特征是它的构建器代码(这里是渲染函数)只有在它被收集时才被执行,因此它是一个 流。

    您也可以参考Asynchronous Flow的文档

    【讨论】:

      【解决方案3】:

      考虑到 Flow 是 Kotlin 的一部分,而 LiveData 是 androidx.lifecycle 库的一部分,我认为 Flow 被用作干净架构中用例的一部分(不依赖于框架)。

      另一方面,LiveData 具有生命周期意识,因此与 ViewModel 匹配

      目前我的所有架构都使用 livedata,但 Flow 看起来是一个值得研究和采用的有趣话题。

      【讨论】:

        猜你喜欢
        • 2020-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-29
        相关资源
        最近更新 更多