Kotlin掛起函數(shù)的詳細(xì)介紹
Kotlin 協(xié)程的優(yōu)勢:
- 解決回調(diào)地獄的問題。
- 以同步的方式完成異步任務(wù)。
示例:
fun main() {
runBlocking {
val a = getA()
println(a)
val b = getB(a)
println(b)
val c = getC(b)
println(c)
}
}
suspend fun getA(): String {
withContext(Dispatchers.IO) {
delay(2000L)
}
return "A content"
}
suspend fun getB(a: String): String {
withContext(Dispatchers.IO) {
delay(2000L)
}
return "$a B content"
}
suspend fun getC(b: String): String {
withContext(Dispatchers.IO) {
delay(2000L)
}
return "$b C content"
}
輸出
A content
A content B content
A content B content C content
suspend關(guān)鍵字修飾的方法 就是 掛起函數(shù)。掛起函數(shù)具備掛起和恢復(fù)的能力。掛起就是將程序執(zhí)行流程轉(zhuǎn)移到其他線程,主線程不阻塞。掛起函數(shù)的本質(zhì)是Callback。
Kotlin編譯器檢測到suspend關(guān)鍵字修飾的函數(shù),會(huì)將掛起函數(shù)轉(zhuǎn)換成帶有CallBack的函數(shù)。
suspend fun getA(): String {
withContext(Dispatchers.IO) {
delay(5000L)
println("now in A process:" + Thread.currentThread())
}
/**
* 這里的代碼涉及掛起函數(shù)中的操作。
*/
println("finish A process:" + Thread.currentThread())
return "A content"
}將上述Kotlin代碼轉(zhuǎn)換成java代碼。
@Nullable
public static final Object getA(@NotNull Continuation var0) {
Object $continuation;
label20: {
if (var0 instanceof <undefinedtype>) {
$continuation = (<undefinedtype>)var0;
if ((((<undefinedtype>)$continuation).label & Integer.MIN_VALUE) != 0) {
((<undefinedtype>)$continuation).label -= Integer.MIN_VALUE;
break label20;
}
}
$continuation = new ContinuationImpl(var0) {
// $FF: synthetic field
Object result;
int label;
@Nullable
public final Object invokeSuspend(@NotNull Object $result) {
this.result = $result;
this.label |= Integer.MIN_VALUE;
return TestCoroutinue2Kt.getA(this);
}
};
}
Object $result = ((<undefinedtype>)$continuation).result;
Object var4 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
switch(((<undefinedtype>)$continuation).label) {
case 0:
ResultKt.throwOnFailure($result);
CoroutineContext var10000 = (CoroutineContext)Dispatchers.getIO();
Function2 var10001 = (Function2)(new Function2((Continuation)null) {
int label;
@Nullable
public final Object invokeSuspend(@NotNull Object $result) {
Object var3 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
switch(this.label) {
case 0:
ResultKt.throwOnFailure($result);
this.label = 1;
if (DelayKt.delay(5000L, this) == var3) {
return var3;
}
break;
case 1:
ResultKt.throwOnFailure($result);
break;
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
String var2 = "now in A process:" + Thread.currentThread();
System.out.println(var2);
return Unit.INSTANCE;
}
@NotNull
public final Continuation create(@Nullable Object value, @NotNull Continuation completion) {
Intrinsics.checkNotNullParameter(completion, "completion");
Function2 var3 = new <anonymous constructor>(completion);
return var3;
}
public final Object invoke(Object var1, Object var2) {
return ((<undefinedtype>)this.create(var1, (Continuation)var2)).invokeSuspend(Unit.INSTANCE);
}
});
((<undefinedtype>)$continuation).label = 1;
if (BuildersKt.withContext(var10000, var10001, (Continuation)$continuation) == var4) {
return var4;
}
break;
case 1:
ResultKt.throwOnFailure($result);
break;
default:
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
}
String var1 = "finish A process:" + Thread.currentThread();
System.out.println(var1);
return "A content";
}注意:runBlocking 的第二個(gè)參數(shù) 也是 傳入一個(gè) suspend修飾的函數(shù) 即掛起函數(shù)。
public actual fun <T> runBlocking(context: CoroutineContext, block: suspend CoroutineScope.() -> T): T {可以發(fā)現(xiàn)上面的Continuation 是一個(gè)帶有泛型參數(shù)的Callback,這里的轉(zhuǎn)換稱為CPS轉(zhuǎn)換,將原本的同步掛起函數(shù)轉(zhuǎn)換成CallBack異步代碼。
/**
* Interface representing a continuation after a suspension point that returns a value of type `T`.
*/
@SinceKotlin("1.3")
public interface Continuation<in T> {
/**
* The context of the coroutine that corresponds to this continuation.
*/
public val context: CoroutineContext
/**
* Resumes the execution of the corresponding coroutine passing a successful or failed [result] as the
* return value of the last suspension point.
*/
public fun resumeWith(result: Result<T>)
}注意:掛起函數(shù),只能在協(xié)程中被調(diào)用,或者被其他掛起函數(shù)調(diào)用。
為什么掛起函數(shù)可以調(diào)用掛起函數(shù),而普通函數(shù)不能調(diào)用掛起函數(shù)?
fun main() {
doA() //這里會(huì)報(bào)錯(cuò)
}
suspend fun doA() {
} public static final void main() {
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
} @Nullable
public static final Object doA(@NotNull Continuation $completion) {
return Unit.INSTANCE;
}被調(diào)用的掛起函數(shù)需要傳入一個(gè)Continuation, 沒有被suspend修飾的函數(shù)是沒有Continuation參數(shù)的,所以沒法在普通函數(shù)中調(diào)用掛起函數(shù),普通函數(shù)沒有Continuation。
掛起函數(shù)最終都是在協(xié)程中被調(diào)用,協(xié)程提供了掛起函數(shù)運(yùn)行的環(huán)境。
到此這篇關(guān)于Kotlin掛起函數(shù)的詳細(xì)介紹的文章就介紹到這了,更多相關(guān)Kotlin掛起函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android 通知使用權(quán)(NotificationListenerService)的使用
這篇文章主要介紹了Android 通知使用權(quán)(NotificationListenerService)的使用的相關(guān)資料,需要的朋友可以參考下2017-06-06
解決android studio 3.0 加載項(xiàng)目過慢問題--maven倉庫選擇
這篇文章主要介紹了android studio 3.0 加載項(xiàng)目過慢問題解決方案---maven倉庫選擇,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-11-11
flutter實(shí)現(xiàn)點(diǎn)擊事件
這篇文章主要為大家詳細(xì)介紹了flutter實(shí)現(xiàn)點(diǎn)擊事件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08
Android簡單實(shí)用的可拖拽GridView組件分享
在我們?nèi)粘i_發(fā)中,使用?GridView?這種網(wǎng)格視圖的場合還是不少的,本篇我們來介紹一個(gè)支持拖拽的?GridView?組件,可以輕松搞定網(wǎng)格視圖的拖拽排序,需要的可以參考一下2023-06-06
Android通過自定義View實(shí)現(xiàn)隨機(jī)驗(yàn)證碼
這篇文章主要介紹了Android通過自定義View實(shí)現(xiàn)隨機(jī)驗(yàn)證碼的相關(guān)資料,需要的朋友可以參考下2016-03-03
詳解Android中Handler的內(nèi)部實(shí)現(xiàn)原理
這篇文章主要介紹了Android中Handler的內(nèi)部實(shí)現(xiàn)原理,對Handler和消息循環(huán)的實(shí)現(xiàn)原理進(jìn)行源碼分析,需要的朋友可以參考下2015-12-12

