You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin协程异常处理疑问:两种async调用为何结果不同?

Kotlin协程async异常处理差异解析

问题现象

使用以下抛出异常的挂起函数:

private suspend fun getMoreUsers(): ArrayList<User> {
    Timber.e("getMoreUsers task started : ${Thread.currentThread().name}")
    delay(1000)
    Timber.e("getMoreUsers task finished")
    throw IllegalStateException("exception thrown manually")
    val list = arrayListOf<User>()
    list.add(User("Deepu", 13))
    return list
}

不崩溃的代码

lifecycleScope.launch {
    try {
        val result = lifecycleScope.async { getMoreUsers() }
        val user = result.await()
    } catch (exception: Exception) {
        Timber.d("$exception handled !")
    }
}

崩溃的代码

lifecycleScope.launch {
    try {
        val result = async { getMoreUsers() }
        val user = result.await()
    } catch (exception: Exception) {
        Timber.d("$exception handled !")
    }
}

崩溃堆栈

java.lang.IllegalStateException: exception thrown manually handled !
4246-4246   E  FATAL EXCEPTION: main
                Process: com.vicky7230.learncoroutines, PID: 4246
                java.lang.IllegalStateException: exception thrown manually
                    at com.vicky7230.learncoroutines.MainActivity.getMoreUsers(MainActivity.kt:68)
                    at com.vicky7230.learncoroutines.MainActivity.access$getMoreUsers(MainActivity.kt:12)
                    at com.vicky7230.learncoroutines.MainActivity$getMoreUsers$1.invokeSuspend(Unknown Source:14)
                    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                    at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:235)
                    at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:168)
                    at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:474)
                    at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:508)
                    at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:497)
                    at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuationImpl.kt:595)
                    at kotlinx.coroutines.android.HandlerContext$scheduleResumeAfterDelay$$inlined$Runnable$1.run(Runnable.kt:19)
                    at android.os.Handler.handleCallback(Handler.java:942)
                    at android.os.Handler.dispatchMessage(Handler.java:99)
                    at android.os.Looper.loopOnce(Looper.java:201)
                    at android.os.Looper.loop(Looper.java:288)
                    at android.app.ActivityThread.main(ActivityThread.java:7872)
                    at java.lang.reflect.Method.invoke(Native Method)
                    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
                    Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@e983b76, Dispatchers.Main.immediate]

原因解析

核心差异在于协程上下文的继承关系和async的异常传播规则:

1. 独立作用域async(不崩溃场景)

lifecycleScope.async是直接通过lifecycleScope这个独立作用域创建的协程,它与外层launch属于完全分离的协程任务:

  • 这种async的异常会被封装在返回的Deferred对象中,只有调用await()时才会抛出异常,因此外层的try-catch可以正常捕获处理,不会将异常传播给其他协程。
  • 独立作用域的协程有自己的异常处理链路,不依赖外层launch的上下文。

2. 父协程上下文继承的async(崩溃场景)

直接调用async时,该协程会继承当前launch协程的上下文,成为launch的子协程:

  • Kotlin协程默认规则:非独立作用域创建的子协程抛出异常时,会立即传播给父协程,而非等待await()调用。
  • 即使在await()处添加了try-catch,异常在抛出时已经传递给父协程(launch),而lifecycleScope的默认异常处理逻辑会将未捕获的协程异常转为应用崩溃。

解决方案

如果要在launch内部使用async且避免崩溃,可以用supervisorScope包裹,它会改变子协程的异常传播规则:

lifecycleScope.launch {
    supervisorScope {
        try {
            val result = async { getMoreUsers() }
            val user = result.await()
        } catch (exception: Exception) {
            Timber.d("$exception handled !")
        }
    }
}

supervisorScope下的子协程异常不会自动传播给父协程,必须通过await()主动获取并处理。


内容的提问来源于stack exchange,提问作者Vicky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 05:45:08