暂停协程直到条件为真

Thi*_*sel 5 kotlin kotlin-coroutines

我有一个用例,我需要连接和断开作为服务的类。只有在服务连接时才能对服务执行操作。当服务连接或断开时通过回调通知客户端:

class Service {

    constructor(callback: ConnectionCallback) { ... }

    fun connect() {
        // Call callback.onConnected() some time after this method returns.
    }

    fun disconnect() {
        // Call callback.onConnectionSuspended() some time after this method returns.
    }

    fun isConnected(): Boolean { ... }

    fun performAction(actionName: String, callback: ActionCallback) {
        // Perform a given action on the service, failing with a fatal exception if called when the service is not connected.
    }

    interface ConnectionCallback {
        fun onConnected() // May be called multiple times
        fun onConnectionSuspended() // May be called multiple times
        fun onConnectionFailed()
    }
}
Run Code Online (Sandbox Code Playgroud)

我想Service使用 Kotlin 协程为该类(我无法控制)编写一个包装器。这是一个骨架ServiceWrapper

class ServiceWrapper {
    private val service = Service(object : ConnectionCallback { ... })

    fun connect() {
        service.connect()
    }

    fun disconnect() {
        service.disconnect()
    }

    suspend fun performActionWhenConnected(actionName: String): ActionResult {
        suspendUntilConnected()

        return suspendCoroutine { continuation ->
            service.performAction(actionName, object : ActionCallback() {
                override fun onSuccess(result: ActionResult) {
                    continuation.resume(result)
                }

                override fun onError() {
                    continuation.resumeWithException(RuntimeException())
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如何suspendUntilConnected()使用 Coroutines实现这种行为?提前致谢。

Mar*_*nik 6

以下是您可以如何实施它:

class ServiceWrapper {
    @Volatile
    private var deferredUntilConnected = CompletableDeferred<Unit>()

    private val service = Service(object : ConnectionCallback {
        override fun onConnected() {
            deferredUntilConnected.complete(Unit)
        }

        override fun onConnectionSuspended() {
            deferredUntilConnected = CompletableDeferred()
        }
    })

    private suspend fun suspendUntilConnected() = deferredUntilConnected.await()

    ...
}
Run Code Online (Sandbox Code Playgroud)

一般注意事项:仅仅因为服务在某个时间点连接并不能保证在您使用它时它仍然会连接。