启动一个协程,然后内部启动子协程,那么最内层如果发生异常,是怎么传递异常的?
val rootExceptionHandler = CoroutineExceptionHandler { _, throwable -> println("调用【根】协程异常处理器:${throwable.message}") }
val parentExceptionHandler = CoroutineExceptionHandler { _, throwable -> println("调用【父】协程异常处理器:${throwable.message}") }
val selfExceptionHandler = CoroutineExceptionHandler { _, throwable -> println("调用【自身】协程异常处理器:${throwable.message}") }
val childExceptionHandler = CoroutineExceptionHandler { _, throwable -> println("调用【子】协程异常处理器:${throwable.message}") }
//即child无效,有self用self,没有self用parent,没有parent用root,同时设置self、parent、root用最近的self
CoroutineScope(Job()).launch(rootExceptionHandler) {
launch(SupervisorJob()+parentExceptionHandler) {
launch(SupervisorJob()+selfExceptionHandler) {
launch(childExceptionHandler) {
throw Exception("子协程使用的是SupervisorJob")
}
}
}
}
反编译源码可得以下代码,看一下是怎么传递的
int $i$f$CoroutineExceptionHandler = false;
CoroutineExceptionHandler.Key var3 = CoroutineExceptionHandler.Key;
CoroutineExceptionHandler rootExceptionHandler = (CoroutineExceptionHandler)(new MainActivity$testException$$inlined$CoroutineExceptionHandler$1(var3));
int $i$f$CoroutineExceptionHandler = false;
CoroutineExceptionHandler.Key var4 = CoroutineExceptionHandler.Key;
final CoroutineExceptionHandler parentExceptionHandler = (CoroutineExceptionHandler)(new MainActivity$testException$$inlined$CoroutineExceptionHandler$2(var4));
int $i$f$CoroutineExceptionHandler = false;
CoroutineExceptionHandler.Key var5 = CoroutineExceptionHandler.Key;
final CoroutineExceptionHandler selfExceptionHandler = (CoroutineExceptionHandler)(new MainActivity$testException$$inlined$CoroutineExceptionHandler$3(var5));
int $i$f$CoroutineExceptionHandler = false;
CoroutineExceptionHandler.Key var6 = CoroutineExceptionHandler.Key;
final CoroutineExceptionHandler childExceptionHandler = (CoroutineExceptionHandler)(new MainActivity$testException$$inlined$CoroutineExceptionHandler$4(var6));
BuildersKt.launch$default(CoroutineScopeKt.CoroutineScope((CoroutineContext)JobKt.Job$default((Job)null, 1, (Object)null)), (CoroutineContext)rootExceptionHandler, (CoroutineStart)null, (Function2)(new Function2((Continuation)null) {
int label;
// $FF: synthetic field
private Object L$0;
public final Object invokeSuspend(Object var1) {
Object var3 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
switch (this.label) {
case 0:
ResultKt.throwOnFailure(var1);
CoroutineScope $this$launch = (CoroutineScope)this.L$0;
BuildersKt.launch$default($this$launch, SupervisorKt.SupervisorJob$default((Job)null, 1, (Object)null).plus((CoroutineContext)parentExceptionHandler), (CoroutineStart)null, (Function2)(new Function2((Continuation)null) {
int label;
// $FF: synthetic field
private Object L$0;
public final Object invokeSuspend(Object var1) {
Object var3 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
switch (this.label) {
case 0:
ResultKt.throwOnFailure(var1);
CoroutineScope $this$launch = (CoroutineScope)this.L$0;
BuildersKt.launch$default($this$launch, SupervisorKt.SupervisorJob$default((Job)null, 1, (Object)null).plus((CoroutineContext)selfExceptionHandler), (CoroutineStart)null, (Function2)(new Function2((Continuation)null) {
int label;
// $FF: synthetic field
private Object L$0;
public final Object invokeSuspend(Object var1) {
Object var3 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
switch (this.label) {
case 0:
ResultKt.throwOnFailure(var1);
CoroutineScope $this$launch = (CoroutineScope)this.L$0;
BuildersKt.launch$default($this$launch, (CoroutineContext)childExceptionHandler, (CoroutineStart)null, (Function2)(new Function2((Continuation)null) {
int label;
public final Object invokeSuspend(Object var1) {
Object var2 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
switch (this.label) {
case 0:
ResultKt.throwOnFailure(var1);
throw new Exception("子协程使用的是SupervisorJob");
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
}
public final Continuation create(Object value, Continuation $completion) {
return (Continuation)(new ($completion));
}
public final Object invoke(CoroutineScope p1, Continuation p2) {
return (()this.create(p1, p2)).invokeSuspend(Unit.INSTANCE);
}
// $FF: synthetic method
// $FF: bridge method
public Object invoke(Object p1, Object p2) {
return this.invoke((CoroutineScope)p1, (Continuation)p2);
}
}), 2, (Object)null);
return Unit.INSTANCE;
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
}
public final Continuation create(Object value, Continuation $completion) {
Function2 var3 = new ($completion);
var3.L$0 = value;
return (Continuation)var3;
}
public final Object invoke(CoroutineScope p1, Continuation p2) {
return (()this.create(p1, p2)).invokeSuspend(Unit.INSTANCE);
}
// $FF: synthetic method
// $FF: bridge method
public Object invoke(Object p1, Object p2) {
return this.invoke((CoroutineScope)p1, (Continuation)p2);
}
}), 2, (Object)null);
return Unit.INSTANCE;
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
}
public final Continuation create(Object value, Continuation $completion) {
Function2 var3 = new ($completion);
var3.L$0 = value;
return (Continuation)var3;
}
public final Object invoke(CoroutineScope p1, Continuation p2) {
return (()this.create(p1, p2)).invokeSuspend(Unit.INSTANCE);
}
// $FF: synthetic method
// $FF: bridge method
public Object invoke(Object p1, Object p2) {
return this.invoke((CoroutineScope)p1, (Continuation)p2);
}
}), 2, (Object)null);
return Unit.INSTANCE;
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
}
public final Continuation create(Object value, Continuation $completion) {
Function2 var3 = new ($completion);
var3.L$0 = value;
return (Continuation)var3;
}
public final Object invoke(CoroutineScope p1, Continuation p2) {
return (()this.create(p1, p2)).invokeSuspend(Unit.INSTANCE);
}
// $FF: synthetic method
// $FF: bridge method
public Object invoke(Object p1, Object p2) {
return this.invoke((CoroutineScope)p1, (Continuation)p2);
}
}), 2, (Object)null);
1、最外层是
BuildersKt.launch$default(CoroutineScopeKt.CoroutineScope((CoroutineContext)JobKt.Job$default((Job)null, 1, (Object)null)), (CoroutineContext)rootExceptionHandler, (CoroutineStart)null, (Function2)(new Function2((Continuation)null) {
}
2、CoroutineScopeKt.CoroutineScope 创建一个带job的作用域,源码如下,如果传递的context有job就使用,如果没有,则给这个context加一个Job()
public fun CoroutineScope(context: CoroutineContext): CoroutineScope = ContextScope(if (context[Job] != null) context else context + Job())
这里是传了一个创建新的job进去 JobKt.Job$default((Job)null, 1, (Object)null)
public static CompletableJob Job$default(Job var0, int var1, Object var2) { return JobKt__JobKt.Job$default(var0, var1, var2); }
JobKt__JobKt.Job$default方法如下,传了参数 (null, 1,null)
public static CompletableJob Job$default(Job var0, int var1, Object var2) { if ((var1 & 1) != 0) { var0 = null; } return JobKt.Job(var0); }
JobKt.Job方法如下,创建一个jobImpl实例,参数从上面可知是null, 也就是parent: Job? = null
public fun Job(parent: Job? = null): CompletableJob = JobImpl(parent)
我们来看一下JobImpl的实现,
internal open class JobImpl(parent: Job?) : JobSupport(true), CompletableJob {
init { initParentJob(parent) }
override val onCancelComplete get() = true
/*
* Check whether parent is able to handle exceptions as well.
* With this check, an exception in that pattern will be handled once:
* ```
* launch {
* val child = Job(coroutineContext[Job])
* launch(child) { throw ... }
* }
* ```
*/
override val handlesException: Boolean = handlesException()
override fun complete() = makeCompleting(Unit)
override fun completeExceptionally(exception: Throwable): Boolean =
makeCompleting(CompletedExceptionally(exception))
@JsName("handlesExceptionF")
private fun handlesException(): Boolean {
var parentJob = (parentHandle as? ChildHandleNode)?.job ?: return false
while (true) {
if (parentJob.handlesException) return true
parentJob = (parentJob.parentHandle as? ChildHandleNode)?.job ?: return false
}
}
}
有个关键方法handlesException(): Boolean 表示是否处理异常的判断,这里代码逻辑就是把
parentHandle转成ChildHandleNode,取出job。
1、如果job为空,则返回false,不处理
2、如果递归向上查找job,找出job不为空,且handlesException消费了异常,则直接返回true
ChildHandleNode是什么玩意?看看,就是子job,保存了parent父节点的job
internal class ChildHandleNode(
@JvmField val childJob: ChildJob
) : JobCancellingNode(), ChildHandle {
override val parent: Job get() = job
override fun invoke(cause: Throwable?) = childJob.parentCancelled(job)
override fun childCancelled(cause: Throwable): Boolean = job.childCancelled(cause)
}
另外我们看看JobImpl的父类JobSupport,这个是Job的关键实现,大部分实现都在这个类,实现对job状态的管理。
JobSupport constructor(active: Boolean) : Job, ChildJob, ParentJob {
继承了job,是有job的生命周期方法,也是个CoroutineContext.Element,可以累加到context里
public interface Job : CoroutineContext.Element
继承了ChildJob,多了方法,父亲取消的调用方法
public interface ChildJob : Job {
/**
* Parent is cancelling its child by invoking this method.
* Child finds the cancellation cause using [ParentJob.getChildJobCancellationCause].
* This method does nothing is the child is already being cancelled.
*
* @suppress **This is unstable API and it is subject to change.**
*/
@InternalCoroutinesApi
public fun parentCancelled(parentJob: ParentJob)
}
继承了ParentJob,getChildJobCancellationCause获取子job取消的异常。
public interface ParentJob : Job {
/**
* Child job is using this method to learn its cancellation cause when the parent cancels it with [ChildJob.parentCancelled].
* This method is invoked only if the child was not already being cancelled.
*
* Note that [CancellationException] is the method's return type: if child is cancelled by its parent,
* then the original exception is **already** handled by either the parent or the original source of failure.
*
* @suppress **This is unstable API and it is subject to change.**
*/
@InternalCoroutinesApi
public fun getChildJobCancellationCause(): CancellationException
}
可以看我之前写的一个协程的启动源码过程 kotlin启动协程源码分析_kotlin 协程源码-CSDN博客
2.1 关键分发协程执行方法 DispatchedTask的run方法
分析代码可知,如果没有被cancel并且context的job也是active状态,其实也是协程的continuation的实现resumeWith方法,会真正执行
continuation.resumeWith(Result.constructor-impl(this.getSuccessfulResult$kotlinx_coroutines_core(state)));
2.2 然后执行的真正的resumeWith方法
取出代理的continuation去执行恢复执行,最后是执行基类的 BaseContinuationImpl.resumeWith
public final void resumeWith(@NotNull Object result) {
Object current = null;
current = this;
Object param = null;
param = result;
while(true) {
DebugProbesKt.probeCoroutineResumed((Continuation)current);
BaseContinuationImpl $this$resumeWith_u24lambda_u240 = (BaseContinuationImpl)current;
int var6 = false;
Continuation var10000 = $this$resumeWith_u24lambda_u240.completion;
Intrinsics.checkNotNull(var10000);
Continuation completion = var10000;
Object outcome;
Result.Companion var12;
try {
outcome = $this$resumeWith_u24lambda_u240.invokeSuspend(param);
if (outcome == IntrinsicsKt.getCOROUTINE_SUSPENDED()) {
return;
}
var12 = Result.Companion;
outcome = Result.constructor-impl(outcome);
} catch (Throwable var11) {
var12 = Result.Companion;
outcome = Result.constructor-impl(ResultKt.createFailure(var11));
}
$this$resumeWith_u24lambda_u240.releaseIntercepted();
if (!(completion instanceof BaseContinuationImpl)) {
completion.resumeWith(outcome);
return;
}
current = completion;
param = outcome;
}
}
可以看到如果协程执行方法invokeSuspend如果发生了异常,则会catch住,分发一个异常返回
outcome = Result.constructor-impl(ResultKt.createFailure(var11));
if (!(completion instanceof BaseContinuationImpl)) {
completion.resumeWith(outcome);
return;
}
这个completion是谁呢?是在哪里传递进来的???????
从我这之前的文章可以知道 kotlin启动协程源码分析_kotlin 协程源码-CSDN博客
在这协程启动的时候
BuildersKt__Builders_commonKt.launch这个方法
@NotNull
public static final Job launch(@NotNull CoroutineScope $this$launch, @NotNull CoroutineContext context, @NotNull CoroutineStart start, @NotNull Function2 block) {
CoroutineContext newContext = CoroutineContextKt.newCoroutineContext($this$launch, context);
StandaloneCoroutine coroutine = start.isLazy() ? (StandaloneCoroutine)(new LazyStandaloneCoroutine(newContext, block)) : new StandaloneCoroutine(newContext, true);
coroutine.start(start, coroutine, block);
return (Job)coroutine;
}
这里一般分支是执行 StandaloneCoroutine,函数关键,把context和父context叠加
public final override val context: CoroutineContext = parentContext + this
调用start方法实现
public final void start(@NotNull CoroutineStart start, Object receiver, @NotNull Function2 block) {
start.invoke(block, receiver, (Continuation)this);
}
继续深入CoroutineStart.invoke方法可以知道是这个completion就是新创建的StandaloneCoroutine
@InternalCoroutinesApi
public final void invoke(@NotNull Function1 block, @NotNull Continuation completion) {
switch (CoroutineStart.WhenMappings.$EnumSwitchMapping$0[this.ordinal()]) {
case 1:
CancellableKt.startCoroutineCancellable(block, completion);
break;
case 2:
ContinuationKt.startCoroutine(block, completion);
break;
case 3:
UndispatchedKt.startCoroutineUndispatched(block, completion);
case 4:
break;
default:
throw new NoWhenBranchMatchedException();
}
}
这里内部是执行分支1,CancellableKt.startCoroutineCancellable,其实内部就是把compleition传进去创建拦截分发器包住嵌套的function,最终把completion传到最底层的Continuation作为参数创建协程continuation
我们来看看这个StandaloneCoroutine也是一个Continuation实现类,看一下他的类继承关系
private open class StandaloneCoroutine(
parentContext: CoroutineContext,
active: Boolean
) : AbstractCoroutine(parentContext, initParentJob = true, active = active) {
override fun handleJobException(exception: Throwable): Boolean {
handleCoroutineException(context, exception)
return true
}
}
继承了AbstractCoroutine抽象类,resumWith方法实现,先调用JobSupport的一个方法makeCompletingOnce,把job的状态标记结束,并处理异常
public final override fun resumeWith(result: Result) {
val state = makeCompletingOnce(result.toState())
if (state === COMPLETING_WAITING_CHILDREN) return
afterResume(state)
}
protected open fun afterResume(state: Any?): Unit = afterCompletion(state)
internal final override fun handleOnCompletionException(exception: Throwable) {
handleCoroutineException(context, exception)
}
把结果转成state进行处理,这里是Result是失败的,那就是个CompletedExceptionally,包住了异常onFailure = { CompletedExceptionally(it) }
internal fun Result.toState(
onCancellation: ((cause: Throwable) -> Unit)? = null
): Any? = fold(
onSuccess = { if (onCancellation != null) CompletedWithCancellation(it, onCancellation) else it },
onFailure = { CompletedExceptionally(it) }
)
调用jobSupport的内联方法,makeCompletingOnce(proposedUpdate: Any?),参数proposedUpdate上面封装好的CompletedExceptionally
@Nullable
public final Object makeCompletingOnce$kotlinx_coroutines_core(@Nullable Object proposedUpdate) {
JobSupport this_$iv = this;
int $i$f$loopOnState = false;
Object finalState;
do {
Object state = this_$iv.getState$kotlinx_coroutines_core();
int var5 = false;
finalState = this.tryMakeCompleting(state, proposedUpdate);
if (finalState == JobSupportKt.access$getCOMPLETING_ALREADY$p()) {
throw new IllegalStateException("Job " + this + " is already complete or completing, but is being completed with " + proposedUpdate, this.getExceptionOrNull(proposedUpdate));
}
} while(finalState == JobSupportKt.access$getCOMPLETING_RETRY$p());
return finalState;
}
再执行下面的方法tryMakeCompleting,这里判断可知执行的是分支
this.tryMakeCompletingSlowPath((Incomplete)state, proposedUpdate);
private final Object tryMakeCompleting(Object state, Object proposedUpdate) {
if (!(state instanceof Incomplete)) {
return JobSupportKt.access$getCOMPLETING_ALREADY$p();
} else if ((state instanceof Empty || state instanceof JobNode) && !(state instanceof ChildHandleNode) && !(proposedUpdate instanceof CompletedExceptionally)) {
return this.tryFinalizeSimpleState((Incomplete)state, proposedUpdate) ? proposedUpdate : JobSupportKt.access$getCOMPLETING_RETRY$p();
} else {
return this.tryMakeCompletingSlowPath((Incomplete)state, proposedUpdate);
}
}
我们看看这个方法tryMakeCompletingSlowPath内部实现
private fun tryMakeCompletingSlowPath(state: Incomplete, proposedUpdate: Any?): Any? {
// get state's list or else promote to list to correctly operate on child lists
val list = getOrPromoteCancellingList(state) ?: return COMPLETING_RETRY
// promote to Finishing state if we are not in it yet
// This promotion has to be atomic w.r.t to state change, so that a coroutine that is not active yet
// atomically transition to finishing & completing state
val finishing = state as? Finishing ?: Finishing(list, false, null)
// must synchronize updates to finishing state
var notifyRootCause: Throwable? = null
synchronized(finishing) {
// check if this state is already completing
if (finishing.isCompleting) return COMPLETING_ALREADY
// mark as completing
finishing.isCompleting = true
// if we need to promote to finishing then atomically do it here.
// We do it as early is possible while still holding the lock. This ensures that we cancelImpl asap
// (if somebody else is faster) and we synchronize all the threads on this finishing lock asap.
if (finishing !== state) {
if (!_state.compareAndSet(state, finishing)) return COMPLETING_RETRY
}
// ## IMPORTANT INVARIANT: Only one thread (that had set isCompleting) can go past this point
assert { !finishing.isSealed } // cannot be sealed
// add new proposed exception to the finishing state
val wasCancelling = finishing.isCancelling
(proposedUpdate as? CompletedExceptionally)?.let { finishing.addExceptionLocked(it.cause) }
// If it just becomes cancelling --> must process cancelling notifications
notifyRootCause = finishing.rootCause.takeIf { !wasCancelling }
}
// process cancelling notification here -- it cancels all the children _before_ we start to to wait them (sic!!!)
notifyRootCause?.let { notifyCancelling(list, it) }
// now wait for children
val child = firstChild(state)
if (child != null && tryWaitForChild(finishing, child, proposedUpdate))
return COMPLETING_WAITING_CHILDREN
// otherwise -- we have not children left (all were already cancelled?)
return finalizeFinishingState(finishing, proposedUpdate)
}
修改job状态为isCompleting = true,通知取消,这里处理job的子job的取消逻辑,通知相关的子节点取消执行。
notifyRootCause?.let { notifyCancelling(list, it) }
private fun notifyCancelling(list: NodeList, cause: Throwable) {
// first cancel our own children
onCancelling(cause)
notifyHandlers(list, cause)
// then cancel parent
cancelParent(cause) // tentative cancellation -- does not matter if there is no parent
}
通知handler,也就是各个节点取消异常。
private inline fun notifyHandlers(list: NodeList, cause: Throwable?) {
var exception: Throwable? = null
list.forEach { node ->
try {
node.invoke(cause)
} catch (ex: Throwable) {
exception?.apply { addSuppressedThrowable(ex) } ?: run {
exception = CompletionHandlerException("Exception in completion handler $node for $this", ex)
}
}
}
exception?.let { handleOnCompletionException(it) }
}
在等待所有子节点取消完成后,我们再看tryMakeCompletingSlowPath里面的的最后一个方法调用
val child = firstChild(state) if (child != null && tryWaitForChild(finishing, child, proposedUpdate)) return COMPLETING_WAITING_CHILDREN // otherwise -- we have not children left (all were already cancelled?) return finalizeFinishingState(finishing, proposedUpdate)
private fun finalizeFinishingState(state: Finishing, proposedUpdate: Any?): Any? {
/*
* Note: proposed state can be Incomplete, e.g.
* async {
* something.invokeOnCompletion {} // <- returns handle which implements Incomplete under the hood
* }
*/
assert { this.state === state } // consistency check -- it cannot change
assert { !state.isSealed } // consistency check -- cannot be sealed yet
assert { state.isCompleting } // consistency check -- must be marked as completing
val proposedException = (proposedUpdate as? CompletedExceptionally)?.cause
// Create the final exception and seal the state so that no more exceptions can be added
val wasCancelling: Boolean
val finalException = synchronized(state) {
wasCancelling = state.isCancelling
val exceptions = state.sealLocked(proposedException)
val finalCause = getFinalRootCause(state, exceptions)
if (finalCause != null) addSuppressedExceptions(finalCause, exceptions)
finalCause
}
// Create the final state object
val finalState = when {
// was not cancelled (no exception) -> use proposed update value
finalException == null -> proposedUpdate
// small optimization when we can used proposeUpdate object as is on cancellation
finalException === proposedException -> proposedUpdate
// cancelled job final state
else -> CompletedExceptionally(finalException)
}
// Now handle the final exception
if (finalException != null) {
val handled = cancelParent(finalException) || handleJobException(finalException)
if (handled) (finalState as CompletedExceptionally).makeHandled()
}
// Process state updates for the final state before the state of the Job is actually set to the final state
// to avoid races where outside observer may see the job in the final state, yet exception is not handled yet.
if (!wasCancelling) onCancelling(finalException)
onCompletionInternal(finalState)
// Then CAS to completed state -> it must succeed
val casSuccess = _state.compareAndSet(state, finalState.boxIncomplete())
assert { casSuccess }
// And process all post-completion actions
completeStateFinalization(state, finalState)
return finalState
}
关键方法
if (finalException != null) { val handled = cancelParent(finalException) || handleJobException(finalException) if (handled) (finalState as CompletedExceptionally).makeHandled() }
这里会先调用取消父亲的cancelParent,如果父亲处理了,则不会用当前context处理 handleJobException了
private fun cancelParent(cause: Throwable): Boolean {
// Is scoped coroutine -- don't propagate, will be rethrown
if (isScopedCoroutine) return true
/* CancellationException is considered "normal" and parent usually is not cancelled when child produces it.
* This allow parent to cancel its children (normally) without being cancelled itself, unless
* child crashes and produce some other exception during its completion.
*/
val isCancellation = cause is CancellationException
val parent = parentHandle
// No parent -- ignore CE, report other exceptions.
if (parent === null || parent === NonDisposableHandle) {
return isCancellation
}
// Notify parent but don't forget to check cancellation
return parent.childCancelled(cause) || isCancellation
}
我们来看看parent.childCancelled(cause)实现 internal class ChildHandleNode( @JvmField val childJob: ChildJob ) : JobCancellingNode(), ChildHandle { override val parent: Job get() = job override fun invoke(cause: Throwable?) = childJob.parentCancelled(job) override fun childCancelled(cause: Throwable): Boolean = job.childCancelled(cause) }
对应job实现
public open fun childCancelled(cause: Throwable): Boolean {
if (cause is CancellationException) return true
return cancelImpl(cause) && handlesException
}
return cancelImpl(cause) && handlesException,这里调用到cancelImpl
internal fun cancelImpl(cause: Any?): Boolean {
var finalState: Any? = COMPLETING_ALREADY
if (onCancelComplete) {
// make sure it is completing, if cancelMakeCompleting returns state it means it had make it
// completing and had recorded exception
finalState = cancelMakeCompleting(cause)
if (finalState === COMPLETING_WAITING_CHILDREN) return true
}
if (finalState === COMPLETING_ALREADY) {
finalState = makeCancelling(cause)
}
return when {
finalState === COMPLETING_ALREADY -> true
finalState === COMPLETING_WAITING_CHILDREN -> true
finalState === TOO_LATE_TO_CANCEL -> false
else -> {
afterCompletion(finalState)
true
}
}
}
又调到相同的方法 cancelMakeCompleting(cause),层层往上传递。
这个调用逻辑可以知道,有点像java的双亲类加载机制,先询问父亲,一直到最顶部处理。如果最顶部没有处理器,则顶部context 也就是StandaloneCoroutine处理handleJobException。
class StandaloneCoroutine extends AbstractCoroutine {
public StandaloneCoroutine(@NotNull CoroutineContext parentContext, boolean active) {
super(parentContext, true, active);
}
protected boolean handleJobException(@NotNull Throwable exception) {
CoroutineExceptionHandlerKt.handleCoroutineException(this.getContext(), exception);
return true;
}
}
这里会有点坑,子协程如果设置了捕获器,会无效,源码分析显示,只会调用到顶部context处理。如果不想只让顶部context处理,只让当前处理,则需要另外一个名字叫监督者,SupervisorJob,重写子chileCancelled方法实现,返回了false
看看一下源码
private class SupervisorJobImpl(parent: Job?) : JobImpl(parent) {
override fun childCancelled(cause: Throwable): Boolean = false
}
结合之前的代码
if (finalException != null) {
val handled = cancelParent(finalException) || handleJobException(finalException)
if (handled) (finalState as CompletedExceptionally).makeHandled()
}
private fun cancelParent(cause: Throwable): Boolean {
.......
// Notify parent but don't forget to check cancellation
return parent.childCancelled(cause) || isCancellation
}
结合分析可知SupervisorJob就是让这里的cancelParent直接写死返回了false,那么cancelParent(finalException)就是false,就会执行到或语句后面的||handleJobException(finalException),也就是当前context的捕获器进行处理了
最后我们来看看handleCoroutineException是如何抛出异常的
public fun handleCoroutineException(context: CoroutineContext, exception: Throwable) {
// Invoke an exception handler from the context if present
try {
context[CoroutineExceptionHandler]?.let {
it.handleException(context, exception)
return
}
} catch (t: Throwable) {
handleUncaughtCoroutineException(context, handlerException(exception, t))
return
}
// If a handler is not present in the context or an exception was thrown, fallback to the global handler
handleUncaughtCoroutineException(context, exception)
}
如果有捕获器,则 it.handleException(context, exception) return
如果没有捕获器,则会执行到
handleUncaughtCoroutineException(context, exception)
internal fun handleUncaughtCoroutineException(context: CoroutineContext, exception: Throwable) {
// use additional extension handlers
for (handler in platformExceptionHandlers) {
try {
handler.handleException(context, exception)
} catch (_: ExceptionSuccessfullyProcessed) {
return
} catch (t: Throwable) {
propagateExceptionFinalResort(handlerException(exception, t))
}
}
try {
exception.addSuppressed(DiagnosticCoroutineContextException(context))
} catch (e: Throwable) {
// addSuppressed is never user-defined and cannot normally throw with the only exception being OOM
// we do ignore that just in case to definitely deliver the exception
}
propagateExceptionFinalResort(exception)
}
最终交给当前线程的捕获器去处理,如果没有设置,其实也就是崩溃crash就发生了
internal actual fun propagateExceptionFinalResort(exception: Throwable) {
// use the thread's handler
val currentThread = Thread.currentThread()
currentThread.uncaughtExceptionHandler.uncaughtException(currentThread, exception)
}