android kotlin 协程源码分析withContext挂载和恢复

协程优点中有一个就是异步代码可以顺序书写,可以避免回调地狱! 是怎么实现的呢?那就来一探究竟。先来个示例代码

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操作,在这里决定是否进行恢复到以前的协程里面

  • 23
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值