2017-07-26 38 views
3

使用kotlinx.coroutines lib如果在協程被取消後拋出異常,我無法捕捉異常。這導致應用程序崩潰。Kotlin協程被取消後無法捕捉異常拋出

fun foo() { 
    val job = launch(UI) { 
    try { 
     Log.d("TAG", "Start coroutine") 
     run(CommonPool) { 
      Log.d("TAG", "Start bg task") 
      // Intentionally make bg task running for a long time 
      SystemClock.sleep(2000) 
      Log.d("TAG", "Throw bg task exception") 
      throw RuntimeException("Bg task exception") 
     } 
    } catch (e: Exception) { 
     Log.e("TAG", "Handle coroutine exception", e) 
    } 
    } 

    launch(UI) { 
    delay(1000) 
    Log.d("TAG", "Cancel job = ${job.cancel()}") 
    } 

}

運行在Android此功能生成以下日誌輸出

07-26 15:09:10.038 31518-31518/co.foo.bar D/MainActivity: Start coroutine 
07-26 15:09:10.044 31518-31547/co.foo.bar D/MainActivity: Start bg task 
07-26 15:09:11.046 31518-31518/co.foo.bar D/MainActivity: Cancel job = true 
07-26 15:09:11.047 31518-31518/co.foo.bar E/MainActivity: Handled coroutine exception 
          java.util.concurrent.CancellationException: Job was cancelled 
          at kotlinx.coroutines.experimental.JobSupport$CompletedExceptionally.getException(Job.kt:921) 
          at kotlinx.coroutines.experimental.RunCompletion.afterCompletion(Builders.kt:198) 
          ... 
          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 
07-26 15:09:12.046 31518-31547/co.foo.bar D/MainActivity: Throwing bg task exception 

--------- beginning of crash 
07-26 15:09:12.046 31518-31547/co.foo.bar E/AndroidRuntime: FATAL EXCEPTION: ForkJoinPool.commonPool-worker-1 
Process: co.foo.bar, PID: 31518 
          java.lang.RuntimeException: Bg task exception 
          at co.foo.barsample.MainActivity$onCreate$1$job$1$1.doResume(MainActivity.kt:36) 
          at kotlin.coroutines.experimental.jvm.internal.CoroutineImpl.resume(CoroutineImpl.kt:54) 
          at kotlinx.coroutines.experimental.DispatchTask.run(CoroutineDispatcher.kt:120) 
          at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1383) 
          at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:256) 
          at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1123) 
          at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1961) 
          at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1909) 
          at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:128) 
07-26 15:09:12.050 1705-2190/system_process W/ActivityManager: Force finishing activity co.foo.bar/co.foo.barsample.MainActivity 

好像是主叫cancel()拋出CancellationException其被成功地捕獲。但隨後的RuntimeException未被捕獲。我認爲作業被取消後的以下異常應該被lib忽略?或者我可以如何在不拋出CancellationException異常的情況下默默取消工作?

+0

你可以把'試穿catch'左右'推出(){}' ? – voddan

+0

@voddan nope,'launch'立即執行。但我找到了解決方案 –

回答

4

使用CoroutineExceptionHandler作爲additinoal協程上下文來處理異常,爲launchrun

run(CommonPool + CoroutineExceptionHandler({ _, e -> 
    Log.e("TAG", "CoroutineExceptionHandler", e) 
})) { 
    ... 
} 

launch(UI + CoroutineExceptionHandler({ _, e -> 
    Log.e("TAG", "CoroutineExceptionHandler", e) 
})) { 
    ... 
} 
+0

感謝您的信息。我們是否應該爲我們的代碼中的每個「啓動」或「運行」用法這樣做?在生產代碼中,我們通常希望異常情況冒泡,以便Crashlytics或其他記錄器可以捕獲它們。有沒有更多...混亂...方式做到這一點? – Pablo

+0

我想問我們是否可以替換「啓動」功能。異步函數以相同的方式捕獲異常?我已經嘗試過並讓它失敗。 至少我可以使用「withContext」函數來使用你的catch異常方法 –