Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.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_Kotlin_Kotlin Coroutines - Fatal编程技术网

Android 如何在协同程序中进行同步API调用?

Android 如何在协同程序中进行同步API调用?,android,kotlin,kotlin-coroutines,Android,Kotlin,Kotlin Coroutines,我需要在for循环中为每个元素调用API,但它必须等待每个API调用返回值,因为如果它是异步的,则返回元素的顺序可能是混合的,因为每个请求都是异步调用 我想在内部等待循环,直到返回值。我为此使用了await(),但它没有按预期工作。在for循环之后返回结果 代码: parts.forEach{p-> 如果(p.listEmpty){ validItems.add(PartItem(不带列表的键入,p)) }否则{ 发射{ val listReturned=getItemsForPart(p) v

我需要在for循环中为每个元素调用API,但它必须等待每个API调用返回值,因为如果它是异步的,则返回元素的顺序可能是混合的,因为每个请求都是异步调用

我想在内部等待循环,直到返回值。我为此使用了
await()
,但它没有按预期工作。在for循环之后返回结果

代码:

parts.forEach{p->
如果(p.listEmpty){
validItems.add(PartItem(不带列表的键入,p))
}否则{
发射{
val listReturned=getItemsForPart(p)
validItems.add(PartItem(键入带有列表的列表,p,listReturned))
}
}
}
private val scope=CoroutineScope(Dispatchers.IO)
private suspend fun getItemsForPart(p:InnerItemPart):列表{
val partResp=CompletableDeferred()
范围.发射{
val parent=api.getParentOfPart(p.partId)
var filteredParts=emptyList()
如果(父项!=null){
val startIndex=parent.innerPart.indexOfFirst{it.partId==p.startId}
val endIndex=parent.innerPart.indexOfFirst{it.partId==p.endId}
filteredParts=parent.subList(startIndex,endIndex).toMutableList()
如果(filteredParts.isNotEmpty())filteredPart.removeAt(0)
}
零件响应完成(过滤零件)
}
返回零件响应等待()
}

当您在
forEach
内部使用
launch
时,您会说启动一个协同程序并将其排入上下文队列,然后让下一个代码运行。所以循环不会挂起(转到下一次迭代,以此类推)

如果您查看定义,它是一个内联函数,这意味着编译时它将在调用站点内联,因此您可以直接在那里使用挂起函数

parts.forEach{p->
如果(p.listEmpty){
validItems.add(PartItem(不带列表的键入,p))
}否则{
val listReturned=getItemsForPart(p)//挂起当前协同路由
validItems.add(PartItem(键入带有列表的列表,p,listReturned))
}
}
您可以使用withContext返回项目,它是轻量级的,并且经过了很好的优化(除非您想要监视子任务,否则您不需要创建CoroutineScope)

private-suspend-fun-getItemsForPart(p:InnerItemPart):列表{
返回withContext(Dispatchers.IO){
//您的旧代码在发布中,只需将filteredParts放在最后一行
过滤零件
}
}

您可以在函数中启动与
Dispatchers.Main
的协同程序,您可以在函数中浏览每个列表项,并在
getItemsForPart()中使用
与上下文(Dispatchers.IO)
<代码>withContext(Dispatchers.IO)
将函数的上下文更改为后台线程:

fun applyForParts() = launch(Dispatchers.Main) {
    parts.forEach { p->
            if (p.listEmpty) {
                validItems.add(PartItem(TYPE_WITHOUT_LIST, p))
            } else {
                val listReturned = getItemsForPart(p) // call blocks for each item
                validItems.add(PartItem(TYPE_WITH_LIST, p, listReturned))
            }
    }
}

private suspend fun getItemsForPart(p: InnerItemPart): List<InnerPart> = withContext(Dispatchers.IO) {
    val parent = api.getParentOfPart(p.partId)
    var filteredParts = emptyList<InnerPart>()
    if (parent != null) {
        val startIndex = parent.innerPart.indexOfFirst { it.partId == p.startId }
        val endIndex = parent.innerPart.indexOfFirst { it.partId == p.endId }
        filteredParts = parent.subList(startIndex, endIndex).toMutableList()
        if (filteredParts.isNotEmpty()) filteredPart.removeAt(0)
    }

    return@withContext filteredParts
}
fun applyForParts()=启动(Dispatchers.Main){
parts.forEach{p->
如果(p.listEmpty){
validItems.add(PartItem(不带列表的键入,p))
}否则{
val listReturned=getItemsForPart(p)//每个项的调用块
validItems.add(PartItem(键入带有列表的列表,p,listReturned))
}
}
}
private-suspend-fun-getItemsForPart(p:InnerItemPart):List=withContext(Dispatchers.IO){
val parent=api.getParentOfPart(p.partId)
var filteredParts=emptyList()
如果(父项!=null){
val startIndex=parent.innerPart.indexOfFirst{it.partId==p.startId}
val endIndex=parent.innerPart.indexOfFirst{it.partId==p.endId}
filteredParts=parent.subList(startIndex,endIndex).toMutableList()
如果(filteredParts.isNotEmpty())filteredPart.removeAt(0)
}
return@withContext过滤零件
}

也许您有我看不到的原因,但仅此挂起函数的作用域看起来不必要,因为您没有使用它来封装取消任务。而CompletableDeferred是不必要的额外复杂性层。使用
withContext
是执行一些后台工作并在完成后将其返回到挂起函数的最简单方法

private suspend fun getItemsForPart(p: InnerItemPart): List<InnerPart> =
    withContext(Dispatchers.IO) {
        val parent = api.getParentOfPart(p.partId)
        var filteredParts = emptyList<InnerPart>()
        if (parent != null){
            val startIndex = parent.innerPart.indexOfFirst { it.partId == p.startId }
            val endIndex = parent.innerPart.indexOfFirst { it.partId == p.endId }
            filteredParts = parent.subList(startIndex, endIndex).toMutableList()
            if (filteredParts.isNotEmpty()) filteredPart.removeAt(0)
        }
        filteredParts
    }
private-suspend-fun-getItemsForPart(p:InnerItemPart):列表=
withContext(Dispatchers.IO){
val parent=api.getParentOfPart(p.partId)
var filteredParts=emptyList()
如果(父项!=null){
val startIndex=parent.innerPart.indexOfFirst{it.partId==p.startId}
val endIndex=parent.innerPart.indexOfFirst{it.partId==p.endId}
filteredParts=parent.subList(startIndex,endIndex).toMutableList()
如果(filteredParts.isNotEmpty())filteredPart.removeAt(0)
}
过滤零件
}
为了进一步简化代码:

private suspend fun getItemsForPart(p: InnerItemPart): List<InnerPart> =
    withContext(Dispatchers.IO) {
        api.getParentOfPart(p.partId)?.let { parent ->
            val startIndex = parent.innerPart.indexOfFirst { it.partId == p.startId }
            val endIndex = parent.innerPart.indexOfFirst { it.partId == p.endId }
            parent.subList(startIndex, endIndex).drop(1)
        }.orEmpty()
    }
private-suspend-fun-getItemsForPart(p:InnerItemPart):列表=
withContext(Dispatchers.IO){
api.getParentOfPart(p.partId)?.let{parent->
val startIndex=parent.innerPart.indexOfFirst{it.partId==p.startId}
val endIndex=parent.innerPart.indexOfFirst{it.partId==p.endId}
子列表(startIndex,endIndex).drop(1)
}.orEmpty()
}

您是否需要仅为此功能创建此单独的作用域?如果不是这样,那就造成了一层不必要的复杂性。正是为了这个。我通常在应用程序API调用中使用asyncTask。我没有在此应用程序中实现协同程序。但稍后在for循环中调用带有返回值的asyncTask是不可能的。它将始终在for循环之后返回。现在又发生了。我需要调用我的大多数项目,但在同一时间,我不想阻止UI线程这一点。在初始化过程中,用户的ProgressBar是可见的。@martin1337您可以使用withContext它是一个顶级函数,为从协同程序返回值进行了高度优化。这是一个迭代的ove
private suspend fun getItemsForPart(p: InnerItemPart): List<InnerPart> =
    withContext(Dispatchers.IO) {
        api.getParentOfPart(p.partId)?.let { parent ->
            val startIndex = parent.innerPart.indexOfFirst { it.partId == p.startId }
            val endIndex = parent.innerPart.indexOfFirst { it.partId == p.endId }
            parent.subList(startIndex, endIndex).drop(1)
        }.orEmpty()
    }