wordpress文章列表添加字段東莞外貿(mào)優(yōu)化公司
suspend修飾符,它可以告訴編譯器,該函數(shù)需要在協(xié)程中執(zhí)行。作為開發(fā)者,您可以把掛起函數(shù)看作是普通函數(shù),只不過它可能會在某些時刻掛起和恢復(fù)而已。協(xié)程的掛起就是退出方法,等到一定條件到來會重新執(zhí)行這個方法,因?yàn)閷Ψ接羞@個協(xié)程的引用,當(dāng)然可以調(diào)用你的方法了。
普通函數(shù)不可以調(diào)用掛起函數(shù)。因?yàn)閽炱鸷瘮?shù)有有一個隱形的參數(shù)Continuation
,普通方法沒有辦法傳Continuation
參數(shù),Continuation
可以簡單理解成java中的Callback
。
suspend修飾的方法不一定真的可以掛起,只要這個方法接收到COROUTINE_SUSPENDED
結(jié)果,就表示可以掛起了,即退出方法。
// 一個普通方法
private fun doFun1() {println("doFun1")
}// 一個suspend修飾的方法,但是方法內(nèi)沒有掛起點(diǎn),方法體可普通方法一樣,但是多一個Continuation參數(shù)
private suspend fun doSuspendFun1(p1: Int) {println("doSuspendFun1")
}// 方法中用了delay方法,delay方法返回了COROUTINE_SUSPENDED
// 表示doSuspendFun2方法在執(zhí)行完delay方法后就會退出
private suspend fun doSuspendFun2(p1: Int, p2: Int) {delay(1000)println("doSuspendFun2")
}fun main() {GlobalScope.launch {println("launch")doSuspendFun2(1, 1)}
}
launch
方法的參數(shù)block
就是一個suspend CoroutineScope.() -> Unit
類型的方法。
我們看下轉(zhuǎn)換成java后的代碼
doFun1
方法沒有什么變化
private static final void doFun1() {System.out.println("doFun1");
}
doSuspendFun1
方法不僅多了一個參數(shù)Continuation
,還多了一個返回值Object
類型,這就是為什么普通函數(shù)不能調(diào)用掛起函數(shù),因?yàn)闊o法傳遞Continuation
參數(shù)。返回值是Object,因?yàn)榭梢苑祷?code>COROUTINE_SUSPENDED,也可以返回String,返回值就是協(xié)程的返回值,所以返回值的類型無法確定。因?yàn)閮?nèi)部沒有使用掛起函數(shù),內(nèi)部的邏輯就和普通方法一樣,就是多一個參數(shù)和一個返回結(jié)果。
private static final Object doSuspendFun1(int p1, Continuation $completion) {System.out.println("doSuspendFun1");return Unit.INSTANCE;
}
來看一下比較復(fù)雜的doSuspendFun2
方法,內(nèi)部使用了delay
方法。就會有掛起點(diǎn),所謂掛起點(diǎn)就是label
,很多文章叫這個為狀態(tài)機(jī)
。執(zhí)行到一個掛起點(diǎn),label
的值就會加1,等下次恢復(fù)的時候,switch
就會知道從哪開始執(zhí)行了。
private static final Object doSuspendFun2(int var0, int var1, Continuation var2) {// Continuation都是從上一個掛起函數(shù)中傳進(jìn)來的,并不是當(dāng)前對象,所以才會重新創(chuàng)建new doSuspendFun2.1(var2)// 防止直接使用外面的的協(xié)程var2,影響到var2。doSuspendFun2.1 $continuation;label20: {// if (var2 instanceof doSuspendFun2.1) {$continuation = (doSuspendFun2.1)var2;if (($continuation.label & Integer.MIN_VALUE) != 0) {$continuation.label -= Integer.MIN_VALUE;break label20;}}// 就是下面的 Test14Kt$doSuspendFun2$1$continuation = new doSuspendFun2.1(var2);}Object $result = $continuation.result;// 它的值就是 COROUTINE_SUSPENDEDObject var5 = IntrinsicsKt.getCOROUTINE_SUSPENDED();switch ($continuation.label) {case 0:ResultKt.throwOnFailure($result);$continuation.getContext();// label加1$continuation.label = 1;if (DelayKt.delay(1000L, $continuation) == var5) {// delay返回 COROUTINE_SUSPENDED,所以直接退出方法return var5;}break;case 1:ResultKt.throwOnFailure($result);break;default:throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");}System.out.println("doSuspendFun2");// 沒有返回值,默認(rèn)就是 Unitreturn Unit.INSTANCE;}
協(xié)程中的Continuation
這樣理解成java中的Callback
,應(yīng)該簡單了吧
掛起方法doSuspendFun2
最后被編譯成一個對象,繼承ContinuationImpl
final class Test14Kt$doSuspendFun2$1 extends ContinuationImpl {// $FF: synthetic fieldObject result;int label;Test14Kt$doSuspendFun2$1(Continuation $completion) {super($completion);}@Nullablepublic final Object invokeSuspend(@NotNull Object $result) {this.result = $result;this.label |= Integer.MIN_VALUE;return Test14Kt.access$doSuspendFun2(0, 0, (Continuation)this);}
}
suspend修飾的方法中如果使用了掛起函數(shù),并且掛起函數(shù)可以返回COROUTINE_SUSPENDED
,jvm就會創(chuàng)建一個繼承自ContinuationImpl
的類,這個類的invokeSuspend
方法就是在執(zhí)行這個掛起方法(此時已經(jīng)被轉(zhuǎn)換成java的普通方法了)。
我們再看看main
函數(shù)里面的launch
處的方法。
final class Test14Kt$main$1 extends SuspendLambda implements Function2 {int label;Test14Kt$main$1(Continuation $completion) {super(2, $completion);}@Nullablepublic final Object invokeSuspend(@NotNull Object $result) {Object var2 = IntrinsicsKt.getCOROUTINE_SUSPENDED();switch (this.label) {case 0:ResultKt.throwOnFailure($result);System.out.println("launch");Continuation var10002 = (Continuation)this;this.label = 1;// 注意把當(dāng)前對象傳給 doSuspendFun2了,這就是Continuation再傳遞 if (Test14Kt.access$doSuspendFun2(1, 1, var10002) == var2) {// 如果doSuspendFun2方法返回COROUTINE_SUSPENDED,也會退出invokeSuspend方法return var2;}break;case 1:ResultKt.throwOnFailure($result);break;default:throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");}return Unit.INSTANCE;}@NotNullpublic final Continuation create(@Nullable Object value, @NotNull Continuation $completion) {return (Continuation)(new Test14Kt$main$1($completion));}@Nullablepublic final Object invoke(@NotNull CoroutineScope p1, @Nullable Continuation p2) {return ((Test14Kt$main$1)this.create(p1, p2)).invokeSuspend(Unit.INSTANCE);}
}
suspend CoroutineScope.() -> Unit
會被編譯繼承SuspendLambda
的一個類。