Kotlin Flow 与 LiveData
Kotlin Flow vs LiveData
在最后 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 一起工作的项目示例。我只找到了 Google 的 ToDo sample,其中协程用于一次性获取数据,然后在更改时手动重新获取数据。
顾名思义,您可以将 Flow 视为多个异步计算值的连续流。在我看来,LiveData 和 Flow 之间的主要区别在于,Flow 会连续发出结果,而 LiveData 会在获取所有数据时更新,并且一次 return 所有值。在您的示例中,您正在获取单个值,这不完全是 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)
}
然后在您的 'Playback' 函数中,您可以显示结果,其中 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 的一个重要特征是它的构建器代码(这里是渲染函数)只有在它被收集时才会执行,因此它是一个 cold 流。
您还可以参考 Asynchronous Flow
中的文档
Flow
有点像 reactive stream
(比如 rxjava)。有许多不同的运算符,例如 .map
、buffer()
(与 rxJava 相比,运算符的数量更少)。因此,LiveData
和 Flow
之间的主要区别之一是您可以使用
在其他线程中订阅地图 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 )
用LiveData
和map
,以上是不能直接实现的!
So its recommended to keep flow in the repository level , and make the livedata a bridge between the UI and the repository !
主要区别在于
- 通常,常规
flow
不 生命周期感知但 liveData
生命周期感知。 (我们可以将 stateFlow 与 repeatOnLifecycle
结合使用以使其具有生命周期意识)
flow
有一堆不同的运算符,livedata
没有!
但同样,这取决于你想如何构建你的项目!
考虑到 Flow 是 Kotlin 的一部分,而 LiveData 是 androidx.lifecycle 库的一部分,我认为 Flow 被用作干净架构中用例的一部分(不依赖于框架)。
另一方面,LiveData 具有生命周期意识,与 ViewModel 的匹配也是如此
目前我的所有架构都使用实时数据,但 Flow 看起来是一个值得研究和采用的有趣主题。
在最后 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 一起工作的项目示例。我只找到了 Google 的 ToDo sample,其中协程用于一次性获取数据,然后在更改时手动重新获取数据。
顾名思义,您可以将 Flow 视为多个异步计算值的连续流。在我看来,LiveData 和 Flow 之间的主要区别在于,Flow 会连续发出结果,而 LiveData 会在获取所有数据时更新,并且一次 return 所有值。在您的示例中,您正在获取单个值,这不完全是 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)
}
然后在您的 'Playback' 函数中,您可以显示结果,其中 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 的一个重要特征是它的构建器代码(这里是渲染函数)只有在它被收集时才会执行,因此它是一个 cold 流。
您还可以参考 Asynchronous Flow
中的文档Flow
有点像 reactive stream
(比如 rxjava)。有许多不同的运算符,例如 .map
、buffer()
(与 rxJava 相比,运算符的数量更少)。因此,LiveData
和 Flow
之间的主要区别之一是您可以使用
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 )
用LiveData
和map
,以上是不能直接实现的!
So its recommended to keep flow in the repository level , and make the livedata a bridge between the UI and the repository !
主要区别在于
- 通常,常规
flow
不 生命周期感知但liveData
生命周期感知。 (我们可以将 stateFlow 与repeatOnLifecycle
结合使用以使其具有生命周期意识) flow
有一堆不同的运算符,livedata
没有!
但同样,这取决于你想如何构建你的项目!
考虑到 Flow 是 Kotlin 的一部分,而 LiveData 是 androidx.lifecycle 库的一部分,我认为 Flow 被用作干净架构中用例的一部分(不依赖于框架)。
另一方面,LiveData 具有生命周期意识,与 ViewModel 的匹配也是如此
目前我的所有架构都使用实时数据,但 Flow 看起来是一个值得研究和采用的有趣主题。