如何在通知之前暂停Kotlin协程

Nem*_*emo 2 kotlin kotlin-coroutines

我想挂起kotlin协程,直到从外部调用方法为止,就像旧的Java object.wait()和object.notify()方法一样。我怎么做?

在这里:正确地在Kotlin中实现wait and notify是如何使用Kotlin线程(阻塞)来实现这一点的答案。在这里:暂停协程直到条件为真才是如何使用CompleteableDeferreds做到这一点的答案,但我不想每次都必须创建一个新的CompleteableDeferred实例。

我目前正在这样做:

    var nextIndex = 0

    fun handleNext(): Boolean {
        if (nextIndex < apps.size) {
            //Do the actual work on apps[nextIndex]
            nextIndex++
        }
        //only execute again if nextIndex is a valid index
        return nextIndex < apps.size
    }

    handleNext()

    // The returned function will be called multiple times, which I would like to replace with something like notify()
    return ::handleNext
Run Code Online (Sandbox Code Playgroud)

来自:https : //gitlab.com/SuperFreezZ/SuperFreezZ/blob/master/src/superfreeze/tool/android/backend/Freezer.kt#L69

Ale*_*nov 7

通道可用于此目的(尽管它们更通用):

当容量为0时,它将创建RendezvousChannel。该通道根本没有任何缓冲区。仅当发送和接收调用在时间上相遇(交会)时,元素才会从发送方转移到接收方,因此发送暂停,直到另一个协程调用接收,接收暂停,直到另一个协程调用send。

所以创造

val channel = Channel<Unit>(0)
Run Code Online (Sandbox Code Playgroud)

并使用channel.receive()for object.wait()channel.offer(Unit)for object.notify()(或者send如果您想等到其他协程receive)。

对于notifyAll,您可以BroadcastChannel改用。

您当然可以轻松地封装它:

inline class Waiter(private val channel: Channel<Unit> = Channel<Unit>(0)) {

    suspend fun doWait() { channel.receive() }
    fun doNotify() { channel.offer(Unit) }
}
Run Code Online (Sandbox Code Playgroud)


Eug*_*nko 5

可以为此使用基本suspendCoroutine{..}功能,例如

class SuspendWait() {
  private lateinit var myCont: Continuation<Unit>
  suspend fun sleepAndWait() = suspendCoroutine<Unit>{ cont ->
    myCont = cont
  }

  fun resume() {
    val cont = myCont
    myCont = null
    cont.resume(Unit)
  }
}
Run Code Online (Sandbox Code Playgroud)

很明显,代码有问题,例如myCont字段未同步,预计sleepAndWait在之前调用resume等等,希望现在思路清晰。

Mutexkotlinx.coroutines 库中的类还有另一个解决方案。

class SuspendWait2 {
  private val mutex = Mutex(locaked = true)
  suspend fun sleepAndWait() = mutex.withLock{}
  fun resume() {
    mutex.unlock()
  }
}
Run Code Online (Sandbox Code Playgroud)