Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 进行多个协同路由API调用并等待所有调用_Android_Retrofit_Coroutine_Kotlin Coroutines_Suspend - Fatal编程技术网

Android 进行多个协同路由API调用并等待所有调用

Android 进行多个协同路由API调用并等待所有调用,android,retrofit,coroutine,kotlin-coroutines,suspend,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.isS

因此,通常当您必须进行不同的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)
    }
}
viewModelScope.launch{
withContext(dispatcherProvider.heavyTasks){
val multipleIds=listOf(1,2,3,4,5,…)
val content=arrayListOf()
multipleIds.forEach{id->
val apiResponse1=api.get1(id)//挂起函数
if(apiResponse1.issusccessful()){
content.find{it.id==id}.enable=true
}
}
liveData.postValue(内容)
}
}

第二种方法的问题是,它将遍历
multipleID
列表的所有ID并进行异步调用,但
内容可能会在这之前发布。我如何等待每个循环的所有响应完成,然后才查看内容的
postValue

而不是
forEach
,使用
map
并在{}块内执行同样的操作。将映射结果保存到变量并发布此变量。

为了获得并发行为,您需要为每个id启动一个新的协同程序。您可以将
多个id
内容
移动到
与上下文
块的外部。您还可以在
withContext
块之后发布结果,因为
withContext
是一个挂起函数,所以在内部创建的每个协同程序都必须在发布结果之前完成

viewModelScope.launch {
    val multipleIds = listOf(1, 2, 3, 4, 5, ..)
    val content = arrayListOf<CustomObj>()

    withContext(dispatcherProvider.heavyTasks) {
        multipleIds.forEach { id ->
            launch {
                val apiResponse = api.get(id) //suspend function
                if (apiResponse.isSuccessful()) {
                    content.find { it.id == id }?.enable = true
                }
            }
        }
    }

    liveData.value = content
}
viewModelScope.launch{
val multipleIds=listOf(1,2,3,4,5,…)
val content=arrayListOf()
withContext(dispatcherProvider.heavyTasks){
multipleIds.forEach{id->
发射{
val apiResponse=api.get(id)//挂起函数
if(apiResponse.issusccessful()){
content.find{it.id==id}?.enable=true
}
}
}
}
liveData.value=内容
}

确保完成两个异步任务的首选方法是使用
coroutineScope
。它将挂起,直到所有子作业(例如对
launch
async
的所有调用)完成为止

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)
    }
}

当我在liveData.value上设置断点时,使用
async
并在主题上等待可能会有所帮助-它总是按预期工作,所有列表项都为true(api.get(id)-已调用且响应已得到),但当我在没有断点的情况下运行代码时,所有列表项都为false(日志显示api调用成功),这意味着,这一反应来得晚。这是行不通的。
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)
    }
}