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

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

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)
    }
}

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

相关推荐
千里马学框架18 小时前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台18 小时前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone18 小时前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc19 小时前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo20 小时前
Kotlin 协程中的 Job 结构化并发与取消
android
sun00770021 小时前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone1 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen1 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone1 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui