Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use coroutines to make a function return a value obtained in a callback

I'm fairly new to async development and specially coroutines. What I'm saying is basically that I don't even know if what I'm trying to achieve is possible or not.

I have a method called sendAudioMessage that I want to return a string. Here is the (obfuscated) code:

override suspend fun sendAudioMessage(): String {
   // ... Do some stuff
   val listener: WebSocketUtils.Listener = object: WebSocketUtils.Listener {
      // ... some (not relevant) functions
      override fun onDisconnect(code: Int, reason: String?) {
         //Do some stuff
         return "myResult -> $code" //This obviously doesn't compile since is trying to make onDisconnect return a string instead of Unit
      }
   }
}

And then I want to call that like this:

override fun send(request: String) {
    CoroutineScope(IO).launch {
        val response = d.sendAudioMessage()
        analyzeResponse( response, request )
    }
}

Is this even possible? If so, how can I achieve this?

like image 736
Luis Fernandez Avatar asked Oct 24 '25 15:10

Luis Fernandez


1 Answers

You need to wrap your callbacks inside a suspendCancellableCoroutine block in order to turn your blocking API call into a suspending function, so you can call it from a coroutine. It works like this:

suspend fun sendAudioMessage(): String = suspendCancellableCoroutine { continuation ->
    WebSocketUtils.Listener {
        // ... some (not relevant) functions
        override fun onDisconnect(code: Int, reason: String?) {
            //Do some stuff
            when (code) {
                OK -> continuation.resume("myResult -> $code")
                ERROR -> continuation.resumeWithException(Exception(reason))
            }
        }
    }
}

When your API call returns successfully you can return the result to your coroutine calling continuation.resume with the result as argument.

When your API call returns with an error you can throw an exception calling continuation.resumeWithException.

Now you can call sendAudioMessage inside a coroutine and work with its result as usual:

class MyClass: CoroutineScope by CoroutineScope(Dispatchers.Default) {
    
    ...
    
    override fun send(request: String) {
        launch(Dispatchers.IO) {
            val response = d.sendAudioMessage()
            analyzeResponse(response, request)
        }
    }
    
    ...
}
like image 111
Glenn Sandoval Avatar answered Oct 26 '25 15:10

Glenn Sandoval



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!