使用协程使函数返回在回调中获得的值

Lui*_*dez 3 kotlin kotlin-coroutines

我对异步开发特别是协程相当陌生。我想说的基本上是,我什至不知道我想要实现的目标是否可能。

我有一个名为sendAudioMessage我想返回字符串的方法。这是(混淆的)代码:

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
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

然后我想这样称呼它:

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

这可能吗?如果是这样,我怎样才能实现这一目标?

Gle*_*val 8

您需要将回调包装在一个suspendCancellableCoroutine块中,以便将阻塞 API 调用转换为挂起函数,以便您可以从协程中调用它。它的工作原理如下:

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))
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当您的 API 调用成功返回时,您可以将结果返回给协程调用continuation.resume,并将结果作为参数。

当您的 API 调用返回错误时,您可以抛出异常调用continuation.resumeWithException

现在您可以sendAudioMessage在协程内部调用并像往常一样处理其结果:

class MyClass: CoroutineScope by CoroutineScope(Dispatchers.Default) {
    
    ...
    
    override fun send(request: String) {
        launch(Dispatchers.IO) {
            val response = d.sendAudioMessage()
            analyzeResponse(response, request)
        }
    }
    
    ...
}
Run Code Online (Sandbox Code Playgroud)