协程优点中有一个就是异步代码可以顺序书写,可以避免回调地狱! 是怎么实现的呢?那就来一探究竟。先来个示例代码
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
MainScope().launch {
Log.i("dxy" ,"log start ")
withContext(Dispatchers.IO){
//这里利用withcontext挂载了一个协程,运行在io线程
Thread.sleep(1000L)
}
Log.i("dxy" ,"log end ")
}
}
}
代码片段1
根据kotlin协程代码分析launch这边连接我们知道,我们的业务代码会生成一个匿名内部类,其父类继承SuspendLambda,反编译代码如下()
public final class MainActivity extends AppCompatActivity {
/* JADX INFO: Access modifiers changed from: protected */
@Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BuildersKt__Builders_commonKt.launch$default(CoroutineScopeKt.MainScope(), null, null, new MainActivity$onCreate$1(null), 3, null);
}
}
final class MainActivity$onCreate$1 extends SuspendLambda implements Function2<CoroutineScope, Continuation<? super Unit>, Object> {
int label;
/* JADX INFO: Access modifiers changed from: package-private */
public MainActivity$onCreate$1(Continuation<? super MainActivity$onCreate$1> continuation) {
super(2, continuation);
}
@Override // kotlin.coroutines.jvm.internal.BaseContinuationImpl
public final Continuation<Unit> create(Object obj, Continuation<?> continuation) {
return new MainActivity$onCreate$1(continuation);
}
@Override // kotlin.jvm.functions.Function2
public final Object invoke(CoroutineScope coroutineScope, Continuation<? super Unit> continuation) {
return ((MainActivity$onCreate$1) create(coroutineScope, continuation)).invokeSuspend(Unit.INSTANCE);
}
@Override // kotlin.coroutines.jvm.internal.BaseContinuationImpl
public final Object invokeSuspend(Object $result) {
Object coroutine_suspended = IntrinsicsKt.getCOROUTINE_SUSPENDED();
switch (this.label) {
case 0:
ResultKt.throwOnFailure($result);
Log.i("dxy", "log start ");
this.label = 1;
if (BuildersKt.withContext(Dispatchers.getIO(), new AnonymousClass1(null), this) != coroutine_suspended) {
break;
} else {
return coroutine_suspended;
}
case 1:
ResultKt.throwOnFailure($result);
break;
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
Log.i("dxy", "log end ");
return Unit.INSTANCE;
}
/* JADX INFO: Access modifiers changed from: package-private */
/* compiled from: MainActivity.kt */
@Metadata(d1 = {"\u0000\n\n\u0000\n\u0002\u0010\u0002\n\u0002\u0018\u0002\u0010\u0000\u001a\u00020\u0001*\u00020\u0002H\u008a@"}, d2 = {"<anonymous>", "", "Lkotlinx/coroutines/CoroutineScope;"}, k = 3, mv = {1, 6, 0}, xi = 48)
@DebugMetadata(c = "com.dxy.myapplication.MainActivity$onCreate$1$1", f = "MainActivity.kt", i = {}, l = {}, m = "invokeSuspend", n = {}, s = {})
/* renamed from: com.dxy.myapplication.MainActivity$onCreate$1$1 reason: invalid class name */
/* loaded from: classes3.dex */
public static final class AnonymousClass1 extends SuspendLambda implements Function2<CoroutineScope, Continuation<? super Unit>, Object> {
int label;
AnonymousClass1(Continuation<? super AnonymousClass1> continuation) {
super(2, continuation);
}
@Override // kotlin.coroutines.jvm.internal.BaseContinuationImpl
public final Continuation<Unit> create(Object obj, Continuation<?> continuation) {
return new AnonymousClass1(continuation);
}
@Override // kotlin.jvm.functions.Function2
public final Object invoke(CoroutineScope coroutineScope, Continuation<? super Unit> continuation) {
return ((AnonymousClass1) create(coroutineScope, continuation)).invokeSuspend(Unit.INSTANCE);
}
@Override // kotlin.coroutines.jvm.internal.BaseContinuationImpl
public final Object invokeSuspend(Object obj) {
IntrinsicsKt.getCOROUTINE_SUSPENDED();
switch (this.label) {
case 0:
ResultKt.throwOnFailure(obj);
Thread.sleep(1000L);
return Unit.INSTANCE;
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
}
}
}
代码片段2
launch会执行到MainActivity$onCreate$1的invokeSuspend方法,然后执行
BuildersKt.withContext(Dispatchers.getIO(), new AnonymousClass1(null), this) != coroutine_suspended这个方法返回false(挂载函数的返回COROUTINE_SUSPENDED)
几个result赋值位置的value都为COROUTINE_SUSPENDED,invokeSuspend代码返回COROUTINE_SUSPENDED,回到resumeWith方法调用invokeSuspend的位置
public final override fun resumeWith(result: Result<Any?>) {
// This loop unrolls recursion in current.resumeWith(param) to make saner and shorter stack traces on resume
var current = this
var param = result
while (true) {
// Invoke "resume" debug probe on every resumed continuation, so that a debugging library infrastructure
// can precisely track what part of suspended callstack was already resumed
probeCoroutineResumed(current)
with(current) {
val completion = completion!! // fail fast when trying to resume continuation without completion
val outcome: Result<Any?> =
try {
val outcome = invokeSuspend(param)
if (outcome === COROUTINE_SUSPENDED) return
Result.success(outcome)
} catch (exception: Throwable) {
Result.failure(exception)
}
releaseIntercepted() // this state machine instance is terminating
if (completion is BaseContinuationImpl) {
// unrolling recursion via loop
current = completion
param = outcome
} else {
// top-level completion reached -- invoke and return
completion.resumeWith(outcome)
return
}
}
}
}
代码片段3
可以看到协程执行暂时结束,状态跃迁this.label = 1;方便后续回来继续执行接下来的内容
看看如何开启一个子协程的,根据代码片段2里面的内容,会把当前的协程传递到新的子协程里面AnonymousClass1 ,它也是SuspendLambda 的子类。
public suspend fun <T> withContext(
context: CoroutineContext,
block: suspend CoroutineScope.() -> T
): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return suspendCoroutineUninterceptedOrReturn sc@ { uCont ->
// compute new context
val oldContext = uCont.context
// Copy CopyableThreadContextElement if necessary
val newContext = oldContext.newCoroutineContext(context)
// always check for cancellation of new context
newContext.ensureActive()
// FAST PATH #1 -- new context is the same as the old one
//新老协程context是否相等,本例子这里为false
if (newContext === oldContext) {
val coroutine = ScopeCoroutine(newContext, uCont)
return@sc coroutine.startUndispatchedOrReturn(coroutine, block)
}
// FAST PATH #2 -- the new dispatcher is the same as the old one (something else changed)
// `equals` is used by design (see equals implementation is wrapper context like ExecutorCoroutineDispatcher)
//这里分发器是否相等,本例子不相等
if (newContext[ContinuationInterceptor] == oldContext[ContinuationInterceptor]) {
val coroutine = UndispatchedCoroutine(newContext, uCont)
// There are changes in the context, so this thread needs to be updated
withCoroutineContext(newContext, null) {
return@sc coroutine.startUndispatchedOrReturn(coroutine, block)
}
}
// SLOW PATH -- use new dispatcher
val coroutine = DispatchedCoroutine(newContext, uCont)
block.startCoroutineCancellable(coroutine, coroutine)
coroutine.getResult()
}
}
代码片段4
这里没有找到suspendCoroutineUninterceptedOrReturn方法的源码位置,通过反编译如下
public static final <T> Object withContext(CoroutineContext context, Function2<? super CoroutineScope, ? super Continuation<? super T>, ? extends Object> function2, Continuation<? super T> continuation) {
Object result;
CoroutineContext oldContext = continuation.getContext();
CoroutineContext newContext = CoroutineContextKt.newCoroutineContext(oldContext, context);
JobKt.ensureActive(newContext);
if (newContext == oldContext) {
ScopeCoroutine coroutine = new ScopeCoroutine(newContext, continuation);
result = UndispatchedKt.startUndispatchedOrReturn(coroutine, coroutine, function2);
} else if (Intrinsics.areEqual(newContext.get(ContinuationInterceptor.Key), oldContext.get(ContinuationInterceptor.Key))) {
UndispatchedCoroutine coroutine2 = new UndispatchedCoroutine(newContext, continuation);
Object oldValue$iv = ThreadContextKt.updateThreadContext(newContext, null);
try {
Object startUndispatchedOrReturn = UndispatchedKt.startUndispatchedOrReturn(coroutine2, coroutine2, function2);
ThreadContextKt.restoreThreadContext(newContext, oldValue$iv);
result = startUndispatchedOrReturn;
} catch (Throwable th) {
ThreadContextKt.restoreThreadContext(newContext, oldValue$iv);
throw th;
}
} else {
DispatchedCoroutine coroutine3 = new DispatchedCoroutine(newContext, continuation);
CancellableKt.startCoroutineCancellable$default(function2, coroutine3, coroutine3, null, 4, null);
result = coroutine3.getResult();
}
if (result == IntrinsicsKt.getCOROUTINE_SUSPENDED()) {
DebugProbesKt.probeCoroutineSuspended(continuation);
}
return result;
}
代码片段5
所以可以知道我们的MainActivity$onCreate$1作为DispatchedCoroutine的成员uCont
internal fun <R, T> (suspend (R) -> T).startCoroutineCancellable(
receiver: R, completion: Continuation<T>,
onCancellation: ((cause: Throwable) -> Unit)? = null
) =
runSafely(completion) {
createCoroutineUnintercepted(receiver, completion).intercepted().resumeCancellableWith(Result.success(Unit), onCancellation)
}
代码片段6
这个代码标识AnonymousClass1对象进行分发运行,和 kotlin协程代码分析launch里面的代码片段8 之后的内容相似,这里不做介绍。我们根据业务代码,子协程切换到io线程后,执行AnonymousClass1的resumeWith方法,根据代码片段3的内容,invokeSuspend子协程业务执行完毕后,会进行if判断,completion的类型,AnonymousClass1的成员completion为DispatchedCoroutine,所以直接执行completion.resumeWith
DispatchedCoroutine-->ScopeCoroutine-->AbstractCoroutine
public final override fun resumeWith(result: Result<T>) {
val state = makeCompletingOnce(result.toState())
if (state === COMPLETING_WAITING_CHILDREN) return
afterResume(state)
}
override fun afterResume(state: Any?) {
if (tryResume()) return // completed before getResult invocation -- bail out
// Resume in a cancellable way because we have to switch back to the original dispatcher
uCont.intercepted().resumeCancellableWith(recoverResult(state, uCont))
}
代码片段7
这个uCont为MainActivity$onCreate$1,进行拦截,intercepted()之后为DispatchedContinuation,然后
@InternalCoroutinesApi
public fun <T> Continuation<T>.resumeCancellableWith(
result: Result<T>,
onCancellation: ((cause: Throwable) -> Unit)? = null
): Unit = when (this) {
is DispatchedContinuation -> resumeCancellableWith(result, onCancellation)
else -> resumeWith(result)
}
代码片段8
inline fun resumeCancellableWith(
result: Result<T>,
noinline onCancellation: ((cause: Throwable) -> Unit)?
) {
val state = result.toState(onCancellation)
if (dispatcher.isDispatchNeeded(context)) {
_state = state
resumeMode = MODE_CANCELLABLE
dispatcher.dispatch(context, this)
} else {
executeUnconfined(state, MODE_CANCELLABLE) {
if (!resumeCancelled(state)) {
resumeUndispatchedWith(result)
}
}
}
}
代码片段9
通过所持有的分发器,再切换原来的线程进行任务执行。我们知道再次执行invokeSuspend的时候,label为1,继续执行主线程的业务逻辑。
新建子协程业务会封装到SuspendLambda的实现类里面,这个对象依附在一个协程AbstractCoroutine的实现类里面,当业务完成,会通知AbstractCoroutine实现类,进行resumeWith操作,在这里决定是否进行恢复到以前的协程里面