android - 从 Android 中的挂起函数并行调用 Kotlin 协程
问题描述
我对协程比较陌生,所以我想知道如何解决我的本地小问题,而无需大量重组我的 Android 代码。
这是一个简单的设置。我的 ViewModelsuspend
从存储库调用一个函数:
// ...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()
可能的/允许的/好的做法吗?
解决方案
您可以为此使用async
和。awaitAll
您需要一个协程范围来启动新的协程,但您可以使用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()
推荐阅读
- react-native - React-native -run-ios 错误无法构建 iOS 项目。我们运行了“xcodebuild”命令,但它以错误代码 65 退出
- javascript - 将 jQuery 函数 insertBefore() 转换为 before() 以附加隐藏的输入
- fortran - 如何让 fortran 等待多个外部进程完成?
- c# - 从简单的 XML 数据列表生成报告或电子表格
- python - 如何嵌套用于自动化目的的输入变量的脚本?
- ant - 如何在 Hybris 中为 WSDL 文件生成 Java 类?
- java - 从命令行运行 java 时如何创建自定义选项
- excel - Excel - 过滤 150 个值
- html - 使此布局具有响应性,没有重复元素
- git - Git - 文件在 github 上,但也在 .gitignore - git pull 上会发生什么?