Kotlin掛起函數的詳細介紹
Kotlin 協(xié)程的優(yōu)勢:
- 解決回調地獄的問題。
- 以同步的方式完成異步任務。
示例:
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關鍵字修飾的方法 就是 掛起函數。掛起函數具備掛起和恢復的能力。掛起就是將程序執(zhí)行流程轉移到其他線程,主線程不阻塞。掛起函數的本質是Callback。
Kotlin編譯器檢測到suspend關鍵字修飾的函數,會將掛起函數轉換成帶有CallBack的函數。
suspend fun getA(): String { withContext(Dispatchers.IO) { delay(5000L) println("now in A process:" + Thread.currentThread()) } /** * 這里的代碼涉及掛起函數中的操作。 */ println("finish A process:" + Thread.currentThread()) return "A content" }
將上述Kotlin代碼轉換成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 的第二個參數 也是 傳入一個 suspend修飾的函數 即掛起函數。
public actual fun <T> runBlocking(context: CoroutineContext, block: suspend CoroutineScope.() -> T): T {
可以發(fā)現(xiàn)上面的Continuation 是一個帶有泛型參數的Callback,這里的轉換稱為CPS轉換,將原本的同步掛起函數轉換成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>) }
注意:掛起函數,只能在協(xié)程中被調用,或者被其他掛起函數調用。
為什么掛起函數可以調用掛起函數,而普通函數不能調用掛起函數?
fun main() { doA() //這里會報錯 } 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; }
被調用的掛起函數需要傳入一個Continuation, 沒有被suspend修飾的函數是沒有Continuation參數的,所以沒法在普通函數中調用掛起函數,普通函數沒有Continuation。
掛起函數最終都是在協(xié)程中被調用,協(xié)程提供了掛起函數運行的環(huán)境。
到此這篇關于Kotlin掛起函數的詳細介紹的文章就介紹到這了,更多相關Kotlin掛起函數內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Android提高之BroadcastReceiver實例詳解
這篇文章主要介紹了Android的BroadcastReceiver用法,在Android的項目開發(fā)中是比較實用的功能,需要的朋友可以參考下2014-08-08如何在原有Android項目中快速集成React Native詳解
創(chuàng)建一個React Native項目并寫一個純的 React Native 應用可以參考官方指南。下面這篇文章主要給大家介紹了關于如何在原有Android項目中快速集成React Native的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下。2017-12-12Android SeekBar 自定義thumb旋轉動畫效果
某些音樂播放或者視頻播放的界面上,資源還在加載時,進度條的原點(thumb)會顯示一個轉圈的效果。這篇文章主要介紹了Android SeekBar 自定義thumb thumb旋轉動畫效果,需要的朋友可以參考下2021-11-11詳解Android業(yè)務組件化之URL Schema使用
這篇文章主要為大家詳細介紹了Android業(yè)務組件化之URL Schema使用,感興趣的小伙伴們可以參考一下2016-09-09Android開發(fā)實現(xiàn)ImageView加載攝像頭拍攝的大圖功能
這篇文章主要介紹了Android開發(fā)實現(xiàn)ImageView加載攝像頭拍攝的大圖功能,涉及Android基于ImageView的攝像頭拍攝圖片加載、保存及權限控制等相關操作技巧,需要的朋友可以參考下2017-11-11