android - 进行多个协程 API 调用并等待所有调用

标签 android retrofit coroutine kotlin-coroutines suspend

因此,通常当您必须进行不同的 API 调用并等待时,您会执行以下操作:

viewModelScope.launch {
    withContext(dispatcherProvider.heavyTasks) {
        val apiResponse1 = api.get1() //suspend function
        val apiResponse2 = api.get2() //suspend function

        if (apiResponse1.isSuccessful() && apiResponse2.isSuccessful() { .. }
    }
}
但是如果我必须使用不同的参数执行多个并发的相同 API 调用会发生什么:
viewModelScope.launch {
    withContext(dispatcherProvider.heavyTasks) {
        val multipleIds = listOf(1, 2, 3, 4, 5, ..)
        val content = arrayListOf<CustomObj>()

        multipleIds.forEach { id ->
             val apiResponse1 = api.get1(id) //suspend function

             if (apiResponse1.isSuccessful()) {
                 content.find { it.id == id }.enable = true
             }
        }

        liveData.postValue(content)
    }
}
第二种方法的问题是它将遍历 multipleIds 的所有 ID。列出并进行异步调用,但 content可能会在此之前发布。如何等待每个循环的所有响应完成,然后才 postValue要查看的内容?

最佳答案

确保完成几个异步任务的首选方法是使用 coroutineScope .它将暂停直到所有子作业,例如所有调用 launchasync , 已完成。

viewModelScope.launch {
    withContext(dispatcherProvider.heavyTasks) {
        val multipleIds = listOf(1, 2, 3, 4, 5, ..)
        val content = arrayListOf<CustomObj>()
        
        coroutineScope {
            multipleIds.forEach { id ->
                launch { // this will allow us to run multiple tasks in parallel
                    val apiResponse = api.get(id)
                    if (apiResponse.isSuccessful()) {
                        content.find { it.id == id }.enable = true
                    }
                }
           }
        }  // coroutineScope block will wait here until all child tasks are completed
        
        liveData.postValue(content)
    }
}
如果您对这种相当隐含的方法感到不舒服,您还可以使用更实用的方法,将您的 id 映射到 Deferred 的列表。使用 async然后等待他们所有人。这也将允许您并行运行所有任务,但最终会得到一个按正确顺序排列的结果列表。
viewModelScope.launch {
    withContext(dispatcherProvider.heavyTasks) {
        val multipleIds = listOf(1, 2, 3, 4, 5, ..)
        val content = arrayListOf<CustomObj>()

        val runningTasks = multipleIds.map { id ->
                async { // this will allow us to run multiple tasks in parallel
                    val apiResponse = api.get(id)
                    id to apiResponse // associate id and response for later
                }
        }

        val responses = runningTasks.awaitAll()

        responses.forEach { (id, response) ->
            if (response.isSuccessful()) {
                content.find { it.id == id }.enable = true
            }
        }
      
        liveData.postValue(content)
    }
}

关于android - 进行多个协程 API 调用并等待所有调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62892071/

相关文章:

android - 为什么 ADB 未经授权调试我安装了 AOSP 的设备?

android - 是否有用于 Retrofit 的 'ResponseInterceptor'(作为其对应的 RequestInterceptor)组件?

android - 为什么暂停不适用于 LiveData?

Python:一个函数中有两个 "yield"

android - GCM 无效发件人错误

android - 带有对话框 fragment 的 tabview android.view.WindowManager$BadTokenException :

android - Maven actionbarsherlock - 主题资源不可用

android - 如何在 Android Studio 中将列表字段返回为空列表 "[]"?

android - 如何在 Retrofit 中使用 ssl 证书发出 https 请求

linux - 为什么 Linux 不使用纤程而不是抢占式多任务处理?