首页 > 解决方案 > 等待 Kotlin 中多个回调/lambda 的结果

问题描述

我正在用 Kotlin 制作一个应用程序。到目前为止,我的网络呼叫不必一起使用。我现在需要进行两个并发的网络调用,暂停直到我收到他们的两个响应,然后继续执行。我正在尝试完成这样的事情:

    //first networking call, get resourceOne
    var resourceOne : String?
    Server.asyncRequest(RequestBuilder(endpoints.second, ids, params)) { resource: String?, error: ServiceError? ->
        resourceOne = resource
    }

    //second networking call, get resourceTwo
    var resourceTwo : String?
    Server.asyncRequest(RequestBuilder(endpoints.third, ids, params)) { resource: String?, error: ServiceError? ->
        resourceTwo = resource
    }

    //do something here wiith resourceOne and resourceTwo

我的 asyncRequest 函数的函数头是:

fun asyncRequest(requestBuilder: RequestBuilder, completion: (resource: String?, error: ServiceError?) -> Unit) {

它只是包装了一个 okhttp 请求并进行了一些额外的处理/解析。通常我只会获取结果(资源)并在完成 lambda 中处理它,但由于我需要这两个值,所以我不能在这里这样做。我试过做类似的事情,我的 asyncRequest 函数没有返回类型,所以我无法像链接那样做异步/等待。

标签: asynchronouskotlinokhttp

解决方案


您可以使用CoroutinesFlow来完成,如下所示:

使用块将回调转换为可挂起的函数suspendCancellableCoroutine {...}

suspend fun <T> request(requestBuilder: RequestBuilder): T = suspendCancellableCoroutine { cont ->
    Server.asyncRequest(requestBuilder) { resource: T, error: ServiceError? ->
        if(error != null)
            cont.resumeWithException(error) // Makes the Flow throw an exception
        else
            cont.resume(resource) // Makes the Flow emit a correct result
    }
}

创建一个以发出第一个请求

val resourceOneFlow = flow {
    emit(request<String>(RequestBuilder(endpoints.second, ids, params)))
}

创建一个以发出第二个请求

val resourceTwoFlow = flow {
    emit(request<String>(RequestBuilder(endpoints.third, ids, params)))
}

将两个与运算符结合zip起来:

val requestsResultFlow = resourceOneFlow.zip(resourceTwoFlow) { resourceOne, resourceTwo ->
    // Build whatever you need with resourceOne and resourceTwo here and let it flow
    "$resourceOne $resourceTwo".length // Here I concatenate both strings and return its length
}

使用操作员激活/启动流程collect并使用其结果

requestsResultFlow.collect { length ->
    // Consume the result here
    println("$length") // Here I print the number received
}

您可以在此处获得Flow文档。


推荐阅读