对于这样的 suspend fun :
suspend fun foo(p1 : P1, ..., pn : Pn) : R {
...
suspendFun(...)
...
return resultR
}
其编译期生成的代码类似这样(这里只考虑方法体里只调用了一次 suspend 方法的情况;如果调用了 n 次 suspend 方法,switch 块会被 n - 1 层 label 标签块嵌套包围):
@Nullable
public Object foo(P1 p1, ..., Pn pn, @NotNull Continuation continuation) {
class LocalContinuationImpl extends kotlin.coroutines.jvm.internal.ContinuationImpl {
// 保存 suspend 方法执行结果
Object result;
// 状态机状态标记
int label;
// 用于保存局部临时变量
Object L$0;
...
Object L$x;
public LocalContinuationImpl(@Nullable Continuation<Object> completion) {
super(completion);
}
@Nullable
@Override
protected Object invokeSuspend(@NotNull Object lastResult) {
result = lastResult;
label |= Integer.MIN_VALUE;
return foo(null, ..., null, this); // 恢复执行时重新调用 foo() 方法,除了最后一个 continuation 参数,其他的参数都是 null 值。
}
}
LocalContinuationImpl localContinuation;
block_label:
{
if (continuation instanceof LocalContinuationImpl) { // 说明这是恢复执行 foo() 方法
localContinuation = (LocalContinuationImpl) continuation;
if ((localContinuation.label & Integer.MIN_VALUE) != 0) {
localContinuation.label -= Integer.MIN_VALUE;
break block_label;
}
}
localContinuation = new LocalContinuationImpl(continuation); // 说明这是第一次执行 foo() 方法
}
Object lastResult = localContinuation.result;
Object state = IntrinsicsKt.getCOROUTINE_SUSPENDED();
Object newResult;
switch (localContinuation.label) {
case 0:
... // 执行 suspendFun() 方法之前的代码
localContinuation.label = 1; // 设置下一次恢复执行的状态
newResult = suspendFun(..., localContinuation);
if (newResult == state /*COROUTINE_SUSPENDED*/) {
return state; // suspendFun() 返回 COROUTINE_SUSPENDED,说明需要挂起 foo() 方法的执行
}
break; // suspendFun() 立即返回结果值,说明不需要挂起 foo() 方法的执行,break 后继续执行 suspendFun() 方法之后的代码,返回最终结果。
case 1:
... // 恢复 localContinuation 保存的临时变量 L$0, ..., L$x
newResult = lastResult;
break;
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
... // 执行 suspendFun() 方法之后的代码
Object finalResult = ... // 计算最终结果值
return finalResult;
}
例如以下代码:
suspend fun test(prefix: String): String {
var ret = prefix
val suffix = withContext(Dispatchers.Default) {
"test"
}
ret += suffix
return ret
}
编译期间生成的代码类似这样:
@Nullable
public static Object test(String prefix, @NotNull Continuation continuation) {
class LocalContinuationImpl extends kotlin.coroutines.jvm.internal.ContinuationImpl {
Object result;
int label;
Object L$0;
public LocalContinuationImpl(@Nullable Continuation<Object> completion) {
super(completion);
}
@Nullable
@Override
protected Object invokeSuspend(@NotNull Object lastResult) {
result = lastResult;
label |= Integer.MIN_VALUE;
return test(null, this);
}
}
LocalContinuationImpl localContinuation;
block_label:
{
if (continuation instanceof LocalContinuationImpl) {
localContinuation = (LocalContinuationImpl) continuation;
if ((localContinuation.label & Integer.MIN_VALUE) != 0) {
localContinuation.label -= Integer.MIN_VALUE;
break block_label;
}
}
localContinuation = new LocalContinuationImpl(continuation);
}
Object lastResult = localContinuation.result;
Object state = IntrinsicsKt.getCOROUTINE_SUSPENDED();
Object newResult;
StringBuilder sb;
switch (localContinuation.label) {
case 0:
ResultKt.throwOnFailure(lastResult);
sb = (new StringBuilder()).append(prefix);
CoroutineContext coroutineContext = Dispatchers.getIO();
WidthContextBlock widthContextBlock = new WidthContextBlock(null);
localContinuation.L$0 = sb;
localContinuation.label = 1;
newResult = BuildersKt.withContext(
coroutineContext,
widthContextBlock,
localContinuation);
if (newResult == state) {
return state;
}
break;
case 1:
sb = (StringBuilder) localContinuation.L$0;
ResultKt.throwOnFailure(lastResult);
newResult = lastResult;
break;
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
String ret = sb.append((String) newResult).toString();
return ret;
}