如何等待函数调用?

时间:2019-11-23 14:51:44

标签: kotlin kotlin-coroutines

所以我发生了一些异步操作,我可以创建一些lambada,调用一个函数并将该值传递给它们。但是我想要的不是将运算结果作为参数,而是要返回它们。

作为一个例子,我有一个带有一些侦听器的类A,如果有结果,将通知所有侦听器。因此,基本上asyncFunction应该返回一个结果,如果有一个结果则被挂起。

object A {
    val listeners = mutableListOf<(Int) -> Unit>()

    fun onResult(value: Int) {
        listeners.forEach { it(value) }
    }
}

fun asyncFunction(): Deferred<Int> {
    return async {
        A.listeners.add({ result ->

        })

        return result
    }
}

我现在正在考虑的事情(也许我完全走错了路)是让Deferred之类的东西发送给我,然后将结果发送给它。有那样的东西吗?我可以自己实施受苦者吗?

class A {
    private val awaiter: ??? // can this be a Deferred ?

    fun onResult(result: Int) {
        awaiter.putResult(result)
    }

    fun awaitResult(): Int  {
        return awaiter.await()
    }
}

val a = A()

launch {
    val result = a.awaitResult()
}

launch {
    a.onResult(42)
}

所以我确实知道可以使用回调进行处理,但是这样做更干净,更容易。

我希望有一个不错,干净的解决方案,而我只是想念它。

1 个答案:

答案 0 :(得分:3)

您的asyncFunction实际上应该是一个可挂起的函数:

suspend fun suspendFunction(): Int =
    suspendCoroutine { cont -> A.listeners.add { cont.resume(it) } }

请注意,它将返回Int结果并暂停直到可用。

但是,这仅是解决您当前问题的方法。它仍然会在许多方面发生故障:

  • 一旦获得第一个结果,侦听器的目的便会得到满足,但它会永远保留在侦听器列表中,从而导致内存泄漏
  • 如果结果在您致电suspendFunction之前到达,它将丢失并挂起。

您可以继续手动进行改进(这是学习的好方法),也可以切换到标准库提供的可靠解决方案。库解决方案为CompletableDeferred

object A {
    val result = CompletableDeferred<Int>()

    fun provideResult(r: Int) {
        result.complete(r)
    }
}

suspend fun suspendFunction(): Int = A.result.await()