我有一个无法控制的API。...其中包含一个可以完成一些工作并异步返回结果的方法。我想在我的应用程序的某些部分中同步调用此方法。我通过添加一个类ResultHandler
来完成此任务,该类捕获并返回结果。是否有比我下面做的更好的方法?也许使用标准的kotlin(或Java作为最后的手段)库方法。我的偏好是让awaitReply
返回结果并删除CountdownLatch
。
class Main {
companion object {
@JvmStatic
fun main(args: Array<String>) {
val result1 = Main().nonAsyncMethod1(arrayListOf(1, 2, 3, 4, 5))
result1.elements.forEach { println(it) }
}
}
class Result1(var elements: Collection<String>)
fun asyncMethod1(x: Collection<Int>, callback: (Result1) -> Unit) {
Thread().run {
// do some calculation
Thread.sleep(1000)
callback(Result1(x.map { "\"$it\"" }.toList()))
}
}
private fun nonAsyncMethod1(entities: Collection<Int>): Result1 {
val resultHandler = ResultHandler<Result1>()
awaitReply<Result1> {
asyncMethod1(entities, resultHandler)
}
return resultHandler.getResponse()
}
open class ResultHandler<T : Any> : (T) -> Unit {
private lateinit var response: T
private val latch = CountDownLatch(1)
override fun invoke(response: T) {
latch.countDown()
this.response = response
}
fun getResponse(): T {
latch.await()
return response
}
}
private fun <T : Any> awaitReply(call: () -> Unit) {
return call.invoke()
}
}
答案 0 :(得分:0)
感谢the_dani的提示
我设法使用了协程作为Kotlin协程文档的“ Wrapping callbacks”部分中详细介绍的以下解决方案:
class Main {
companion object {
@JvmStatic
fun main(args: Array<String>) = runBlocking {
val result1 = Main().nonAsyncMethod1(arrayListOf(1, 2, 3, 4, 5))
result1.elements.forEach { println(it) }
}
}
class Result1(var elements: Collection<String>)
fun asyncMethod1(x: Collection<Int>, callback: (Result1) -> Unit) {
Thread().run {
// do some calculation
Thread.sleep(1000)
callback(Result1(x.map { "\"$it\"" }.toList()))
}
}
suspend fun nonAsyncMethod1(entities: Collection<Int>): Result1 = suspendCoroutine {
cont ->
asyncMethod1(entities) { cont.resume(it) }
}
}
答案 1 :(得分:0)
您可以使用协程将回调函数包装在异步函数中 (协程类似于C#async / await,您可以创建看起来非常同步但可以异步执行的异步代码)
https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md#wrapping-callbacks
有一个简单的模式。假设您有一些LongComputation 带有回调的函数,该函数接收由于 这种计算。
fun someLongComputation(params: Params, callback: (Value) -> Unit)`
您可以使用以下命令将其转换为挂起函数 简单的代码:
suspend fun someLongComputation(params: Params): Value = suspendCoroutine { cont -> someLongComputation(params) { cont.resume(it) } }
只能在协程环境中调用挂起函数(例如,使用launch{ }
),但是要等待,可以使用runBlocking{ }
,然后应等待协程完成。这应该创建您想要的行为。