Hey everybody. I was hoping I could get some help ...
# coroutines
o
Hey everybody. I was hoping I could get some help in how to best approach this situation… I have a suspending function that returns some data. I may need to suspend the coroutine that called the function while something else is done asynchronously, and then resume the coroutine, eventually returning data from that function.
Copy code
suspend fun foo(): Bar {
    // I call another suspend function here returning an intermediate value.
    if (error) {
        suspendCancellableCoroutine<Bar> { continuation ->
            val listener = object : Listener {
                override fun callback() {
                    // I need to call this suspend function again.
                    // However, here is where I get an error.
                    continuation.resume(foo())
                }
            }
            // I call other functions that will eventually call the listener.
        }
    }
}
The error that I get is obvious -
Suspension functions can be called only within coroutine body
. However, I’m not really quite sure on how to resume the coroutine properly. Any help is much appreciated. Thank you.
e
I guess its pretty clear that the issue is that the context that
callback
runs on is not suspending so you cannot call suspending functions inside of it. One thing you can do is use
runBlocking
to wrap the inner
foo
function. Whoever calls outer
foo
is still suspended and when the inner runBlocking returns, outer foo’s caller should be resumed (as intended). But you should also restructure your code. This is what it looks like to me:
Copy code
class Bar

fun interface Listener {
  fun callback()
}

suspend fun doIntermediateStuff(): Boolean = TODO()

suspend fun suspendForCallback() = suspendCancellableCoroutine<Unit> { continuation ->
  val listener = Listener {
    continuation.resume(Unit)
  }
  // someOtherCode.register(listener)
}

suspend fun foo(): Bar {
  val isError = doIntermediateStuff()

  if (isError) {
    suspendForCallback()
    return foo()
  }

  return Bar()
}
c
Another option, rather than using
suspendCancellableCoroutine
would be a
callbackFlow
, which does allow suspending functions to be called within with block
u
As a rule of thumb, do not mix any further logic into suspendCancelableCoroutine. Wrap your callback into a suspend function Aa a single concern. And then solve your business logic with suspend functions
1