【问题标题】:How to proper cancel CoroutineWorker如何正确取消 CoroutineWorker
【发布时间】:2021-06-04 19:03:59
【问题描述】:

我有一个 CoroutineWorker 需要在用户与我的应用交互时启动和停止,所以我使用 awaitCancelation() 方法,如下所示:

override suspend fun doWork(): Result {
        try {
            startListen()
            awaitCancellation()
        } finally {
            stopListen()
            return Result.success()
        }
    }

一切正常,但是当我调用 WorkManager.cancel 并取消我的工作时,WorkerWrapper 会引发内部异常:

I/WM-WorkerWrapper: Work [ id=721c463b-15aa-4daa-988d-a4c080915443, tags={ br.com.example.app.workers.MyWorker, WORKER_TAG } ] was cancelled
    java.util.concurrent.CancellationException: Task was cancelled.
        at androidx.work.impl.utils.futures.AbstractFuture.cancellationExceptionWithCause(AbstractFuture.java:1184)
        at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:514)
        at androidx.work.impl.utils.futures.AbstractFuture.get(AbstractFuture.java:475)
        at androidx.work.impl.WorkerWrapper$2.run(WorkerWrapper.java:300)
        at androidx.work.impl.utils.SerialExecutor$Task.run(SerialExecutor.java:91)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:923)

我没有找到任何其他看起来更合适的方式来阻止我的 CoroutineWorker,同时我觉得这不是阻止它的正确方法。

如果有人知道避免这种情况或抑制这种异常的另一种方法,我将不胜感激。

【问题讨论】:

    标签: kotlin kotlin-coroutines android-workmanager


    【解决方案1】:

    通常情况下,通过抛出CancellationException 来取消我们的可取消后台任务并没有什么问题。抛出异常通常是最容易的,因为它可以自动传播到整个调用堆栈。 Java 在中断线程时使用了相同的技术 - 它抛出 InterruptedException

    但是,如果您确实需要一种更简洁的方式来指示您的后台服务应该停止工作,那么协程库中有很多实用程序可以让您实现这一目标。例如,您可以使用Mutex

    private val mutex = Mutex(true)
    
    override suspend fun doWork(): Result {
            try {
                startListen()
                mutex.lock()
            } finally {
                stopListen()
                return Result.success()
            }
        }
    
    fun stop() {
        mutex.unlock()
    }
    

    由于互斥锁最初处于锁定状态,它将在lock() 处挂起。然后在stop() 中解锁互斥锁,允许第一个协程继续。您可以通过在其上创建CompletableJob 然后join() 等来对信号量、通道执行相同的操作。

    【讨论】:

      猜你喜欢
      • 2013-10-18
      • 2023-03-23
      • 2021-01-08
      • 1970-01-01
      • 2013-08-15
      • 1970-01-01
      • 1970-01-01
      • 2023-02-08
      • 2017-02-12
      相关资源
      最近更新 更多