But there is still one gap. We know that CoroutineDispatcher defines dispatch() to take a CoroutineContext and a Runnable. Here is its signature:
public abstract fun dispatch(context: CoroutineContext, block: Runnable)
So how is it that DispatchedContinuation sends itself as the Runnable, as we just saw? Here is the snippet again:
dispatcher.dispatch(context, this)
As mentioned before, DispatchedContinuation also implements the DispatchedTask interface. This interface extends Runnable by adding a default implementation of run() that can trigger resume() and resumeWithException() in the continuation, as shown here:
public override fun run() {
try {
val delegate = delegate as DispatchedContinuation<T>
val continuation = delegate.continuation
val context = continuation.context
val job = if (resumeMode.isCancellableMode) context[Job] else null
val state = takeState()
withCoroutineContext(context) {
if (job != null && !job.isActive) {
continuation.resumeWithException(
job.getCancellationException())
} else {
val exception = getExceptionalResult(state)
if (exception != null) {
continuation.resumeWithException(exception)
} else {
continuation.resume(getSuccessfulResult(state))
}
}
}
} catch (e: Throwable) {
throw DispatchException("Unexpected exception running $this", e)
}
}
Notice that withCoroutineContext() is called before calling resume(); this guarantees that all elements that are part of the CoroutineContext are set before its execution.