gpt4 book ai didi

android - 从 Android 中的挂起函数并行调用 Kotlin 协程

转载 作者:行者123 更新时间:2023-12-04 23:54:22 26 4
gpt4 key购买 nike

我对协程比较陌生,所以我想知道如何解决我的本地小问题,而无需大量重组我的 Android 代码。

这是一个简单的设置。我的 ViewModel 调用了 suspend来自存储库的功能:

// ...ViewModel.kt

fun loadData() {
viewModelScope.launch {
val data = dataRepository.loadData()
}
}

这很方便,因为我有一个 viewModelScope由 Android 为我准备,我从我的存储库中调用了一个挂起函数。我不在乎存储库如何加载数据,我只是暂停直到它返回给我。

我的数据存储库使用 Retrofit 进行了多次调用:
//...DataRepository.kt

@MainThread
suspend fun loadData(): ... {
// Retrofit switches the contexts for me, just
// calling `suspend fun getItems()` here.
val items = retrofitApi.getItems()
val itemIDs = items.map { it.id }

// Next, getting overall list of subItems for each item. Again, each call and context
// switch for `suspend fun retrofitApi.getSubItems(itemID)` is handled by Retrofit.
val subItems = itemIDs.fold(mutableListOf()) { result, itemID ->
result.apply {
addAll(retrofitApi.getSubItems(itemID)) // <- sequential :(
}
}

return Pair(items, subItems)
}

如您所见,由于 loadData()是一个挂起函数,所有对 retrofitApi.getSubItem(itemID) 的调用将按顺序执行。

但是,我想并行执行它们,例如 async() / await()在协程中会做。

我想保留 ViewModel代码不变——它不应该关心数据是如何加载的,只是从自己的范围内启动一个挂起函数。我也不想将任何类型的范围或其他对象传递到我的存储库。

如何在挂起函数中执行此操作?范围是否以某种方式隐含存在?正在调用 async()可能/允许/良好做法?

最佳答案

您可以使用 asyncawaitAll为了这。您需要一个协程范围来启动新的协程,但您可以使用 coroutineScope 创建一个继承现有上下文的协程。 .

suspend fun loadData(): Pair = coroutineScope {
val items = retrofitApi.getItems()
val itemIDs = items.map { it.id }
val subItems = itemIDs.map { itemID ->
async { retrofitApi.getSubItems(itemID) }
}.awaitAll()
.flatten()

return Pair(items, subItems)
}

您可以使用 flatten在您的原始代码中简化一点。 (只是指出它与分解这些并行任务无关。)它看起来像这样:
val subItems = itemIDs.map { itemID ->
retrofitApi.getSubItems(itemID)
}.flatten()

关于android - 从 Android 中的挂起函数并行调用 Kotlin 协程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60836667/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com