在suspendCoroutine块中调用挂起函数的合适方法是什么?

时间:2020-07-01 01:44:06

标签: android kotlin kotlin-coroutines

在调用suspendCoroutine之前,我需要在continuation.resume()块中调用一个暂停函数。 合适的方法是什么?

private suspend fun someFunction() = suspendCoroutine { cont ->
    //...
    val myResult = mySuspendingFunction() //<--- The IDE says "Suspension functions can be called only within coroutine body"
    cont.resume(myResult)
}

2 个答案:

答案 0 :(得分:1)

您无法在suspendCoroutine块中调用suspend函数,因为它接受非暂挂块作为参数:

suspend inline fun <T> suspendCoroutine(
    crossinline block: (Continuation<T>) -> Unit
): T

'suspendCoroutine'主要在我们有一些带有回调的遗留代码时使用,例如:

suspend fun getUser(id: String): User = suspendCoroutine { continuation ->
      Api.getUser(id) { user ->
          continuation.resume(user)
      }
}

如果函数someFunction()未使用回调调用Api,则您应重新考虑摆脱“ suspendCoroutine”的方法:

private suspend fun someFunction() {
    // ...
    val myResult = mySuspendingFunction()
    // ...
}

如果您仍然想使用suspendCoroutinemySuspendingFunction的调用移出suspendCoroutine块:

private suspend fun someFunction(): String {
    val myResult = mySuspendingFunction()

    return suspendCoroutine { cont ->
        //...
        cont.resume(myResult)
    }
}

suspend fun mySuspendingFunction(): String {
    delay(1000) // simulate request
    return "result"
}

答案 1 :(得分:0)

最好避免这种情况并在 17.5 之前调用挂起函数,正如其他人已经回答的那样。对于所讨论的特定案例,这是可能的。

但是,如果您需要继续,这是不可能的。

(以下内容针对那些因为这个原因发现这个问题的人,就像@Zordid 和我一样。suspendCoroutine 就是一个例子。)

在这种情况下,以下是一种可能但容易出错的方法,我推荐:

chan.send

(我认为单独的错误处理说明了为什么它不是一个很好的选择,尽管还有其他问题。)

如果可以,更好、更安全、更便宜的方法是使用 suspend fun cont1() { //btw. for correct implementation, this should most likely be at least suspendCancellableCoroutine suspendCoroutine<Unit> { uCont -> val x = suspend { chan.send(foo(uCont)) } x.startCoroutine(Continuation(uCont.context) { if (it.isFailure) uCont.resumeWith(it) // else resumed by whatever reads from chan }) } }

如果您必须传入一个Continuation,那么这样做仍然更安全,而且可能更便宜:

CompletableDeferred