协程学习(九)协程简单的使用之异常处理

在上一篇文章中有说过,协程中的异常最初是由下向上抛的,那么我可不可以在 中间层协程中捕获异常呢,下面看一下案例

kotlin 复制代码
@JvmStatic
fun main(array: Array<String>) {
    runBlocking {
        var error=CoroutineExceptionHandler { _, throwable ->
            println("Tsm Error:${throwable}")
        }
       var scope= CoroutineScope(SupervisorJob()+ Dispatchers.IO)
        scope.launch {
            launch {
                launch {
                    launch(error) {
                        launch {
                            throw NullPointerException("我错了")
                        }
                    }
                }
            }
        }
        delay(5*1000)
    }
}

在这里创建了一个新的 CoroutineScope ,指定io线程 与 阻止子协程异常而向导致其他兄弟协程异常退出,最终在最内层的子协程中跑了一个异常,并在倒数第二层的协程中传入了 CoroutineExceptionHandler 想要拦截异常

看一下结果

php 复制代码
Exception in thread "DefaultDispatcher-worker-2 @coroutine#6" java.lang.NullPointerException: 我错了
	at com.tsm.opencv.Tsm$main$1$1$1$1$1$1.invokeSuspend(Tsm.kt:23)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:100)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [CoroutineId(2), "coroutine#2":StandaloneCoroutine{Cancelling}@1397bbe2, Dispatchers.IO]

Process finished with exit code 0

发现这个异常还是引起了崩溃,说明这个异常最终只能抛给顶级父协程来处理,中间协程拦截不了

我们再来看一下 async 的表现

typescript 复制代码
@JvmStatic
fun main(array: Array<String>) {
    runBlocking {
        var error=CoroutineExceptionHandler { _, throwable ->
            println("Tsm Error:${throwable}")
        }
        var scope= CoroutineScope(SupervisorJob()+ Dispatchers.IO)

        scope.async{
            async {
                async {
                    async(error) {
                        async {
                            throw NullPointerException("我错了")
                        }
                    }
                }
            }
        }
        delay(5*1000)
    }
}
结果:
Process finished with exit code 0

虽然抛出了异常但是程序没有接受到这个异常,我们使用await 接受一下结果看一下

swift 复制代码
Exception in thread "main" java.lang.NullPointerException: 我错了
	at com.tsm.opencv.Tsm$main$1$1$1$1$1$1.invokeSuspend(Tsm.kt:44)
	at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt:46)
	at com.tsm.opencv.Tsm$main$1.invokeSuspend(Tsm.kt:49)
Caused by: java.lang.NullPointerException: 我错了
	at com.tsm.opencv.Tsm$main$1$1$1$1$1$1.invokeSuspend(Tsm.kt:44)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:100)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)

Process finished with exit code 1

可以看到我们使用await后异常就出现了,这说明 async 虽然也收到了这个异常,但是只有在await后,才会获取异常或者结果从而将他抛出

下面将异常交给顶级父协程来处理看一下结果

先看一下launch 的表现

kotlin 复制代码
@JvmStatic
fun main(array: Array<String>) {
    runBlocking {
        var error=CoroutineExceptionHandler { _, throwable ->
            println("Tsm Error:${throwable}")
        }
       var scope= CoroutineScope(SupervisorJob()+ Dispatchers.IO)
        scope.launch(error) {
            launch {
                launch {
                    launch{
                        launch {
                            throw NullPointerException("我错了")
                        }
                    }
                }
            }
        }
        delay(5*1000)
    }
}
结果:

Tsm Error:java.lang.NullPointerException: 我错了

Process finished with exit code 0

可以看到异常确实被捕获了

再来看看 async

less 复制代码
@JvmStatic
fun main(array: Array<String>) {
    runBlocking {
        var error = CoroutineExceptionHandler { _, throwable ->
            println("Tsm Error:${throwable}")
        }

        var scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
        var job=scope.async(error) {
            throw NullPointerException("我错了")
        }
        job.await()
        delay(1 * 1000)
    }
}
结果:
Exception in thread "main" java.lang.NullPointerException: 我错了
	at com.tsm.opencv.Tsm$main$1$job$1.invokeSuspend(Tsm.kt:42)
	at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt:46)
	at com.tsm.opencv.Tsm$main$1.invokeSuspend(Tsm.kt:44)
Caused by: java.lang.NullPointerException: 我错了
	at com.tsm.opencv.Tsm$main$1$job$1.invokeSuspend(Tsm.kt:42)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:100)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)

Process finished with exit code 1

可以发现在使用async 的过程中即使使用了 CoroutineExceptionHandler 还是抛出了异常,这个是为什么呢, 原因与我们在上面讲的 只有await 的时候才可以获取 这个异常是一样的, 是因为 async 方法只是创建一个协程,但是异常只有调用了await 才能获取,那么在实际开发中该如何处理这种情况呢

1: 在 async 中使用 try catch 捕获异常,保险起见 CoroutineExceptionHandler 还是要在顶级父协程加上的 方式如下

kotlin 复制代码
@JvmStatic
fun main(array: Array<String>) {
    runBlocking {
        var error = CoroutineExceptionHandler { _, throwable ->
            println("Tsm Error:${throwable}")
        }

        var scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
        var job=scope.async(error) {
            try {
                throw NullPointerException("我错了")
            } catch (e: Exception) {
            }
        }
        job.await()
        delay(1 * 1000)
    }
}

2: 为了保险起见在 async 中同样使用 CoroutineExceptionHandler,但是在 await 出try catch

kotlin 复制代码
@JvmStatic
fun main(array: Array<String>) {
    runBlocking {
        var error = CoroutineExceptionHandler { _, throwable ->
            println("Tsm Error:${throwable}")
        }

        var scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
        var job=scope.async(error) {
            throw NullPointerException("我错了")
        }
        job.runCatching { await() }.getOrElse {

        }
        delay(1 * 1000)
    }
}

3: 使用launch 作为顶级父协程 + CoroutineExceptionHandler

kotlin 复制代码
@JvmStatic
fun main(array: Array<String>) {
    runBlocking {
        var error = CoroutineExceptionHandler { _, throwable ->
            println("Tsm Error:${throwable}")
        }

        var scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
        scope.launch(error) {
            var job = async {
                throw NullPointerException("我错了")
            }
            job.await()
        }
        delay(1 * 1000)
    }
}

可以看到使用第三种方法更为的优雅但是具体选择就看个人的喜好了,

相关推荐
_extraordinary_3 小时前
MySQL 事务(二)
android·数据库·mysql
鸿蒙布道师7 小时前
鸿蒙NEXT开发动画案例5
android·ios·华为·harmonyos·鸿蒙系统·arkui·huawei
橙子1991101613 小时前
在 Kotlin 中什么是委托属性,简要说说其使用场景和原理
android·开发语言·kotlin
androidwork13 小时前
Kotlin Android LeakCanary内存泄漏检测实战
android·开发语言·kotlin
笨鸭先游14 小时前
Android Studio的jks文件
android·ide·android studio
gys989514 小时前
android studio开发aar插件,并用uniapp开发APP使用这个aar
android·uni-app·android studio
H3091914 小时前
vue3+dhtmlx-gantt实现甘特图展示
android·javascript·甘特图
像风一样自由14 小时前
【001】renPy android端启动流程分析
android·gitee
千里马学框架16 小时前
重学安卓14/15自由窗口freeform企业实战bug-学员作业
android·framework·bug·systrace·安卓framework开发·安卓窗口系统·自由窗口
xianrenli3821 小时前
android特许权限调试
android