fra*_*yan 8 android kotlin kotlin-coroutines
我对协程相对较新,所以我想知道如何解决我的本地小问题而不需要大量重组我的 Android 代码。
这是一个简单的设置。我的 ViewModel 从存储库调用一个suspend函数:
// ...ViewModel.kt
fun loadData() {
    viewModelScope.launch {
        val data = dataRepository.loadData()
    }
}
Run Code Online (Sandbox Code Playgroud)
这非常方便,因为我已经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)
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,由于loadData()是一个挂起函数,因此所有对 的调用都retrofitApi.getSubItem(itemID)将按顺序执行。
但是,我想并行执行它们,就像async() / await()在协程中一样。
我想保持ViewModel代码不变 - 它不应该关心数据如何加载,只需从自己的作用域启动一个挂起函数。我也不想将任何类型的范围或其他对象传递到我的存储库。
如何在挂起函数中执行此操作?范围是否以某种方式隐含地存在在那里?打电话async()可能/允许/良好的做法吗?
Ten*_*r04 12
为此,您可以使用asyncand 。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@coroutineScope Pair(items, subItems)
}
Run Code Online (Sandbox Code Playgroud)
flatten您可以在原始代码中使用它来简化它。(只是指出它与分解这些并行任务无关。)它看起来像这样:
val subItems = itemIDs.map { itemID ->
        retrofitApi.getSubItems(itemID)
    }.flatten()
Run Code Online (Sandbox Code Playgroud)
        |   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           14692 次  |  
        
|   最近记录:  |