asynchronous - 等待 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 函数没有返回类型,所以我无法像链接那样做异步/等待。
解决方案
您可以使用Coroutines和Flow来完成,如下所示:
使用块将回调转换为可挂起的函数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文档。
推荐阅读
- angularjs - 在angularJS中打开相同部分视图和控制器的多个实例
- c# - MVC Posting back umbraco
- php - Laravel:当输入是数组时使用验证器的有时方法
- wpf - Shift + 鼠标滚轮水平滚动
- python - SVM 陷入优化
- nsurlsession - 使用 URLSession 和 URLRequest 为 uploadTask 添加内容配置参数
- qt - Qt EventFilter - 一旦事件被事件过滤器消耗,控制永远不会返回到 MouseArea
- python - Python - 无论发生什么异常,我如何让程序永远运行?
- javascript - 如何更改锚标签下载属性的下载路径
- reactjs - 如何使用文件对象设置状态