簡體   English   中英

Android Kotlin 流運算符 - 等待所有流發出

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM