Приостановите сопрограмму, пока условие не станет истинным - PullRequest
0 голосов
/ 23 декабря 2018

У меня есть сценарий использования, когда мне нужно подключиться и отключиться от класса, который действует как служба.Действия могут быть выполнены над сервисом только тогда, когда сервис подключен.Клиенты получают уведомление, когда служба подключается или отключается с помощью обратного вызова:

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()
    }
}

Я хотел бы написать оболочку для этого класса Service (который я не контролирую) с помощью Kotlin Coroutines.Вот скелет из 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())
                }
            }
        }
    }
}

Как я могу реализовать это suspendUntilConnected() поведение с помощью сопрограмм?Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 24 декабря 2018

Вот как вы можете это реализовать:

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()

    ...
}

Общее примечание: только потому, что служба, подключенная в определенный момент, не гарантирует, что она будет подключена к тому времени, когда вы ее используете.

0 голосов
/ 23 декабря 2018

Вы находитесь в приостановленной функции, почему бы не что-то вроде:

while (!service.isConnected()) {
    delay(1000)
}

Вы можете добавить дополнительные условия тайм-аута в это утверждение.

...