【问题标题】:How to fix Kotlin JobCancellationException?如何修复 Kotlin JobCancellationException?
【发布时间】:2020-05-04 12:23:08
【问题描述】:

由于 Kotlin JobCancellationException,我遇到了崩溃。

以下是有关崩溃的详细信息:

kotlinx.coroutines.JobCancellationException: Job was cancelled; job=SupervisorJobImpl{Cancelling}@131dbe3     

我只知道 SupervisorJobImpl 是针对 ViewModelScope 的,当 ViewModel 生命周期结束时,它会被调用方法 cancel

我对异常感到非常困惑,因为 Kotlin 协程只会忽略异常,但它被抛出并导致应用程序崩溃。如果它有堆栈,我可以弄清楚,但它没有,告诉我作业被取消了。

我在异常上花了大约 3 天多的时间,但只是不知道。

我看了视频: KotlinConf 2019: Coroutines! Gotta catch 'em all! by Florina Muntenescu & Manuel Vivo,我发现如果scope被取消了,如果你在Deferred上调用await,它会抛出异常,但是我发现取消的scope上没有await .

那么有人可以向我展示一些可能导致相同异常并使应用程序崩溃的代码吗?谢谢,那里。

【问题讨论】:

  • 您是否手动取消任何内容?您是否正在与取消的工作或范围进行交互?很难说这里有什么问题。
  • 我展示了所有的 ViewModel#aunch 方法,发现无处调用手动取消,只是 ViewModel 内部调用。
  • 你能显示完整的堆栈跟踪吗?
  • 没有更多的堆栈跟踪,这就是我发布问题的原因。
  • 要获得完整的堆栈跟踪,you need to enable coroutines debug mode

标签: android kotlin


【解决方案1】:

终于找到导致异常的原因,问题地址在流动:

kotlin.coroutines.channels.awaitClose: JobCancellationException

其实awaitClose不会抛出JobCancellationException,因为awaitClose是一个可取消的挂起函数。如果 Job 被取消,offer 方法将抛出 JobCancellationException,因为 offer 不是可取消的挂起函数。

顺便说一句,callbackFlow是一个实验性的API,所以可能会引起一些bug,所以我们在使用的时候需要小心。因为它不会在 Job 被取消的时候一直忽略JobCancellationException,而且我认为它对开发者不友好。

现在我发现了两种情况会导致JobCancellationException,所以我们需要try catch这个异常。

  1. async await,当我们调用await方法时,我们需要try catch。您可以在Video 中找到示例。

  2. callbackFlow offer,当我们调用offer方法时,我们需要try catch。您可以在上面的问题中找到一个示例。

【讨论】:

  • 嗨,类似的事情发生在我身上。我将我的工作 = viewModelScope.launch(Dispatchers.IO) { } 包裹在 try-catch 中。仍然没有进入 catch 块的异常。你是如何解决这个问题的?
  • 你不应该将launch包裹在try-catch中,你需要try-catch launch中的代码。
  • @Shrikant 你需要找到导致异常的代码并用try-catch包装。
【解决方案2】:

我知道我迟到了,但您可以在提供物品之前检查工作状态。 像这样

if(isActive) offer(Resource.success(response))

isActive 是协程作用域

【讨论】:

  • 好的,谢谢。 try catch 不是最好的方法,这个更好。
  • 是的。这是最有意义的。如果该工作不再有效,请不要致电 offer。
【解决方案3】:

我刚刚看到了同样的问题。该问题是由在作业成功完成之前手动完成的活动引起的。

【讨论】:

  • 你如何找到otu还有什么工作需要完成?
【解决方案4】:
class MyApp: Application() {

    override fun onCreate() {
        super.onCreate()
        System.setProperty(DEBUG_PROPERTY_NAME, DEBUG_PROPERTY_VALUE_ON)
       
    }

通过这种方式,您将能够查明问题的主要原因并进行处理

【讨论】:

    【解决方案5】:

    我和你有同样的错误。所以我尝试编写如下简单的流程扩展:

    fun <P> Flow<DataResult<P>>.safeStart(start: suspend FlowCollector<DataResult<P>>.() -> Unit)
            : Flow<DataResult<P>> =  onStart {
            if (!currentCoroutineContext().isActive) return@onStart
            start()
        }
    
    fun <P> Flow<DataResult<P>>.safeCatch(onCatch: suspend FlowCollector<DataResult<P>>.(cause: Throwable) -> Unit)
            : Flow<DataResult<P>> = catch {
            if (!currentCoroutineContext().isActive) return@catch
            onCatch(it)
    }
    
    suspend inline fun <P> Flow<DataResult<P>>.safeCollect(crossinline onCollect: suspend (value: DataResult<P>) -> Unit)
            : Unit = collect {
        if (!currentCoroutineContext().isActive) return@collect
        onCollect(it)
    }
    

    【讨论】:

      【解决方案6】:

      我关闭了ViewModel 和一个对话框,然后启动了Job。它导致了这个异常和 HTTP 请求取消:HTTP FAILED: java.io.IOException: Canceled

      close()
      modelScope.launch {
          val response = withContext(Dispatchers.IO) {
              ...
          }
          response?.let { ... }
      }
      

      我只是将close() 移到最后。

      【讨论】:

        【解决方案7】:

        当我将callbackFlowoffer 与协程版本1.3.5 一起使用时,发生了同样的崩溃。 现在我使用 trySend 而不是 offer,它已修复。

        注意: 当您将协程版本更新为:

        org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.0
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-04-23
          • 1970-01-01
          • 1970-01-01
          • 2019-05-16
          • 2020-06-29
          • 2022-12-30
          • 1970-01-01
          相关资源
          最近更新 更多