有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在Kotlin中使异步调用同步

我有一个我无法控制的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()
    }
}

共 (2) 个答案

  1. # 1 楼答案

    您可以使用带有协同路由的回调来包装异步函数 (协同程序类似于C#async/await,您可以创建看起来非常同步但执行异步的异步代码)

    https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md#wrapping-callbacks

    There is a simple pattern. Assume that you have someLongComputation function with callback that receives some Value that is a result of this computation.

    fun someLongComputation(params: Params, callback: (Value) -> Unit)` 
    

    You can convert it into a suspending function with the following straightforward code:

    suspend fun someLongComputation(params: Params): Value = suspendCoroutine { cont ->
        someLongComputation(params) { cont.resume(it) } 
    }
    

    挂起函数只能在协同路由上下文中调用(例如使用launch{ }),但是为了等待,可以使用^{},然后它应该等待协同路由完成。这会产生你想要的行为

  2. # 2 楼答案

    多亏了丹麦人的暗示

    我使用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) }
        }
    }