[英]Android Kotlin flow operator - wait until all flows have emitted
我目前正在學習 Android 上的 Kotlin 流運算符,並希望發出網絡請求或數據庫操作,然后是並行請求並等待所有流返回。
data class Category(var id: Int, var name: String, var parentCategoryId: Int?) {
var subCategories: List<Category> = listOf()
}
data class Catalogue(var categories: List<Category>) {}
// request to fetch top level categories
fun getTopCats(): Flow<List<Category>> {
return flowOf(
listOf(
Category(0, "Dairy", null),
Category(1, "Fruits", null),
Category(2, "Vegetables", null)
)
)
}
// request to fetch sub categories
suspend fun getSubCats(catId: Int): Flow<List<Category>> {
return when (catId) {
0 -> flowOf(listOf(Category(3, "Milk", 0), Category(4, "Butter", 0)))
.onEach { delay(1000) }
1 -> flowOf(
listOf(
Category(5, "Banana", 1),
Category(6, "Mandarin", 1),
Category(7, "Orange", 1)
).onEach { delay(2000) }
)
2 -> flowOf(
listOf(
Category(8, "Carrot", 2),
Category(9, "Asparagus", 2),
Category(10, "Lettuce", 2)
).onEach { delay(3000) }
)
else -> flowOf()
}
}
第一次嘗試 - 我認為我做錯了什么,因為沒有獲取子類別。 我應該在哪里放置組合運算符?
viewModelScope.launch {
val catalogue = Catalogue(listOf())
getTopCats().map {
catalogue.categories = categories // assign top level category
val flows = arrayListOf<Flow<List<Category>>>()
categories.onEach { cat ->
flows.add(getSubCats(cat.id))
}
combine(flows) { array ->
array.onEach { list ->
catalogue.categories[list.first().id].subCategories = list
}
}
catalogue
}.flowOn(Dispatchers.Default).collect() {
Timber.d("Received catalogue object")
}
}
您可以使用combine函數合並多個流並從所有流中收集最新結果。 來自 combine 的文檔:
返回一個流,其值是通過組合每個流最近發出的值,使用轉換函數生成的。
例如:
// Some individual flows to return a single value
val getA = flowOf(1)
val getB = flowOf(2)
val getC = flowOf(3)
// Combine into a single flow that emits a list of the individual
// flow latest results
val combined = combine(getA, getB, getC) { a, b, c ->
// Combine the results into whatever data structure
// you want - here I made a list
listOf(a,b,c)
}
MainScope().launch {
combined.collect { results ->
println("Got $results") // prints [1, 2, 3]
}
}
Combine 還可以獲取任意長度的流列表,如果你有很多的話,它會返回一個值數組(要求所有流返回相同的類型)
val manyFlows = listOf(getA, getB, getC)
val combined = combine(manyFlows) { result ->
// result is an Array<T> where manyFlows is List<Flow<T>>
result.toList()
}
編輯
作為一個更完整的示例,這里是您如何獲取熱門類別列表,然后將它們組合到您使用combine
一次性調用的流列表
suspend fun getData() {
val top = getTopCats()
top.collect { result ->
// Get the result of the first flow
val subcatFlows = result.map { getCatCount(it) }
// Create a new flow to retrieve some count integer
// from each of the top categories
val allSubCats = combine(subcatFlows) { counts ->
// produce a map of categories to counts
result.zip(counts.toList()).toMap()
}
// Call the new combined flow to collect the
// counts all at once
allSubCats.collect { results ->
println("Got $results") // prints {A=1, B=2, C=3}
}
}
}
// request to fetch the count for a given
// category by name
private fun getCatCount(name: String): Flow<Int> {
return when(name) {
"A" -> flowOf(1)
"B" -> flowOf(2)
"C" -> flowOf(3)
else -> flowOf(-1)
}
}
// request to fetch top level categories
private fun getTopCats(): Flow<List<String>> {
return flowOf(listOf("A","B","C"))
}
然后你可以在協程中調用getData()
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.