作业延迟取消后不会再开始

Job delay is not started again after canceling

所以当我按下一个按钮时,我需要等待 3 秒才能执行另一个方法,我用下面的方法解决了这个问题

val job = CoroutineScope(Dispatchers.Main).launch(Dispatchers.Default, CoroutineStart.DEFAULT) {
    delay(THREE_SECONDS)
    if (this.isActive)
        product?.let { listener?.removeProduct(it) }
}



override fun onRemoveProduct(product: Product) {
        job.start()
    }

现在,如果我在开始工作后立即按下取消按钮,我就会停止工作,而且工作正常

 override fun onClick(v: View?) {
        when(v?.id) {
            R.id.dismissBtn -> {
                job.cancel()
            }
        }
    }

问题是,当我再次执行 onRemoveProduct 执行 job.start() 时,它不会再次启动,似乎 job.isActive 永远不会屈服于 true,为什么会这样?

A Job 一旦取消就无法再次开始。你需要以不同的方式做到这一点。一种方法是每次调用 onRemoveProduct 时创建一个新作业。

private var job: Job? = null

fun onRemoveProduct(product: Product) {
    job = scope.launch {
        delay(THREE_SECONDS)
        listener?.removeProduct(product) // Assuming the two products are same. If they aren't you can modify this statement accordingly.
    }
}

fun cancelRemoval() { // You can call this function from the click listener
    job?.cancel()
}

此外,在您的这行代码中 CoroutineScope(Dispatchers.Main).launch(Dispatchers.Default, CoroutineStart.DEFAULT)

  • 您不应该t/needn不自己创建新的协程作用域。您 can/should 使用已经提供的 viewModelScopelifecycleScope。它们是更好的选择,因为它们了解生命周期并在正确的时间被取消。
  • Dispatchers.Main 没用,因为它无论如何都会被 Dispatchers.Default 取代。 Dispatchers.Default 在这里也不是必需的,因为您在这里没有进行任何繁重的计算(或调用一些阻塞代码)。
  • CoroutineStart.DEFAULT 是默认参数,因此您可以跳过该参数。

而且你也不需要检查 if (this.isActive) 因为

If the [Job] of the current coroutine is cancelled or completed while delay is waiting, it immediately resumes with [CancellationException].