协程 与 异常
若子协程抛出异常,只有外层父协程能 handle 到异常,中间层的协程 handle 不到,若外层父协程不 handle , 程序会报错
协程内抛出的异常可以通过传入 CoroutineExceptionHandler
对象去处理,操作符 +
可处理 上下文 和 handler
val handler = CoroutineExceptionHandler { context, throwable ->
toast("未正常支付")
LogUtils.e("${throwable.message}")
}
lifecycleScope.launch(lifecycleScope.coroutineContext + handler) {
withContext(Dispatchers.IO) {
PayTask(this@VipActivity).payV2(orderInfo, true)
}.let {
when (it["resultStatus"]) {
"9000" -> {
toast("支付成功")
refreshPageAfterVip()
}
"6001" -> {
toast("取消支付")
}
else -> {
toast("未正常支付")
}
}
}
}
Job
和 SupervisorJob
的一个区别是,
Job
的子协程发生异常被取消会同时取消 Job
的其它子协程,
而 SupervisorJob
不会。(含有 SupervisorJob
SupervisorCoroutine
或 重写 childCancelled
函数且返回 false
等情况的)
查看代码 Job 实例化
public fun Job(parent: Job? = null): CompletableJob = JobImpl(parent)
查看代码 SupervisorJob 实例化
public fun SupervisorJob(parent: Job? = null) : CompletableJob = SupervisorJobImpl(parent)
再查看,发现原因是重写方法 childCancelled
返回 false
private class SupervisorJobImpl(parent: Job?) : JobImpl(parent) {
override fun childCancelled(cause: Throwable): Boolean = false
}
launch 和 async 是异步, 理论上在代码块外是捕获不到异常
但 saync 搭配 await(同步), 可以在 await 捕获异常
runBlocking withContext 在里外都可以捕获异常
runBlocking 可以在block外面 catch
try {
runBlocking(lifecycleScope.coroutineContext) {
throw RuntimeException("test")
}
} catch (e: Exception) {
Log.e("runBlocking", "catch Exception ${e.message}")
}
launch 必须在block里面 catch
val job = launch(lifecycleScope.coroutineContext) {
try {
throw RuntimeException("test")
} catch (e: Exception) {
Log.e("launch", "catch Exception ${e.message}")
}
}
job.join()
withContext 可以在block外面 catch
try {
val result = withContext(lifecycleScope.coroutineContext) {
throw RuntimeException("test")
}
} catch (e: Exception) {
Log.e("withContext", "withContext Exception ${e.message}")
}
async 可以在block外面 catch,具体是 await 时
try {
val deferred = async(lifecycleScope.coroutineContext) {
throw RuntimeException("test")
}
val result = deferred.await()
} catch (e: Exception) {
Log.e("async", "catch Exception ${e.message}")
}