Сделать синхронный вызов синхронным в Котлине - PullRequest
0 голосов
/ 13 декабря 2018

У меня есть 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 ]

0 голосов
/ 13 декабря 2018

Вы можете обернуть асинхронные функции обратным вызовом с сопрограммами (сопрограммы похожи на C # async / await, вы можете создать асинхронный код, который выглядит очень синхронно, но выполняется асинхронно)

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

Существует простой шаблон.Предположим, что у вас есть функция someLongComputation с обратным вызовом, которая получает некоторое значение, являющееся результатом этого вычисления.

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

Вы можете преобразовать ее в функцию приостановки с помощью следующего простого кода:

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

Функции приостановки можно вызывать только в контексте сопрограммы (например, с помощью launch{ }), но для ожидания можно использовать runBlocking{ }, который должен ждать завершения сопрограммы.,Это должно создать желаемое поведение.

0 голосов
/ 13 декабря 2018

Благодаря подсказке от the_dani

мне удалось прийти к решению, приведенному ниже, с использованием сопрограмм, как описано в разделе " Wrapping callbacks " документации по сопрограммам Kotlin:

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) }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...