繁体   English   中英

使用 Kotlin 协程调用多个 API 请求并等待响应

[英]Calling multiple API requests and waiting for response using Kotlin Coroutines

应用了代码更改。

我遵循了有关如何创建 kotlin 协程和执行网络请求的指南,最终得到:

suspend fun <T : Any> safeApiCall(call: suspend () -> Response<T>): ApiResult<T> {
    return safeApiResult(call)
}

private suspend fun <T: Any> safeApiResult(call: suspend ()-> Response<T>) : ApiResult<T>{
    val response = call.invoke()

    return if (response.isSuccessful) {
        val body = response.body()

        if (body == null) {
            ApiResult.Error(response.code())
        } else {
            ApiResult.Success(body)
        }
    } else {
        ApiResult.Error(response.code())
    }
}

suspend fun getSnappedPoints(path: String): ApiResult<SnappedPointsData> {
    return safeApiCall(
        call = { googleRoadsService.getSnappedPoints(path).await()}
    )
}

并调用网络请求如下所示:

private fun getSnappedPoints() {
    val paths = Utils.getPathFromLocations(locations)

    CoroutineScope(Dispatchers.IO).launch {
        val results = paths.map {
            async { googleRoadsRepository.getSnappedPoints(it) }
        }.awaitAll()

        Timber.i("results: ${results.size}")

        val snappedPoints = ArrayList<LocationSnap>()

        results.forEach {
            if (it is ApiResult.Success) {
                snappedPoints.addAll(it.data.snappedPoints)
            }
        }

        withContext(Dispatchers.Main) {
            if (snappedPoints.isNotEmpty()) {
                drawPolyline(snappedPoints)
            } else {
                showError()
            }
        }
    }
}

当前问题:

当我单击特定项目时调用函数getSnappedPoints() 它第一次实际调用 google API 并且结果 > 0(大小),但是如果我返回并在同一/其他项目getSnappedPoints()二次单击,则调用getSnappedPoints()paths不是 Empty,但不知何故它确实如此不调用googleRoadsRepository.getSnappedPoints(it)并且有点跳过调试中的那一步,我能看到的只是结果始终为 0。什么可能导致这种情况?

每个协程( launch )都是一个并发单元,如果你想并发运行每个请求,你必须为每个并发请求做一个launch / async

private fun getPoints() {
    val multipleParams = Utils.getArrayListOfParams()

    coroutineJob = CoroutineScope(Dispatchers.IO).launch {
        val results = multipleParams.map {
            async { Repository.getPoints(it) }
        }.awaitAll()

        // Do something with results, once all have been gotten.
        // result and result2, result[it] has finished, continue)
    }
}

奖金:

  • 如果您创建CoroutineScope而不取消它,那么您应该使用GlobalScope作为优化。 (像这样GlobalScope.launch(Dispatchers.IO)
  • 您不需要Dispatchers.IO来执行此操作,因为您似乎没有阻塞协程/线程。 Dispatchers.Default会做得很好。
  • 我不确定您使用coroutineJob变量的目的,但它看起来很可疑。

当您在 IO 线程时,使用async + await的必要性是什么? 在 IO 范围内,您可以自由挂起并等待响应。

试试这个并通知我知道结果会怎样?

private fun getSnappedPoints() {
val paths = Utils.getPathFromLocations(locations)

CoroutineScope(Dispatchers.IO).launch {
    val results = paths.map {
        googleRoadsRepository.getSnappedPoints(it)
    }

    // rest of you code...
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM