亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Kotlin掛起函數(shù)應(yīng)用介紹

 更新時間:2022年11月22日 10:20:32   作者:且聽真言  
掛起函數(shù)用狀態(tài)機(jī)以掛起點將協(xié)程的運算邏輯拆分成不同的片段,每次執(zhí)行協(xié)程運行不同的邏輯片段,由此可以知道協(xié)程是運行在線程中的,線程的并發(fā)處理方式也可以用在協(xié)程上

學(xué)習(xí)了極客時間課程,記錄下學(xué)習(xí)輸出。

一、CPS轉(zhuǎn)換

掛起函數(shù),比普通的函數(shù)多了 suspend 關(guān)鍵字。通過suspend 關(guān)鍵字,Kotlin 編譯器就會特殊對待這個函數(shù),將其轉(zhuǎn)換成一個帶有 Callback 的函數(shù),這里的 Callback 就是 Continuation 接口。

例、CPS 轉(zhuǎn)換:

suspend fun getUserInfo(): Any {
    return "UserInfo"
}
----->
fun getUserInfo(ct:Continuation): Any? {
    ct.resumeWith("UserInfo")
    return Unit
}

PS 轉(zhuǎn)換過程中,函數(shù)的類型發(fā)生了變化:suspend ()->Any 變成了 (Continuation)-> Any?。這意味著,如果你在 Java 里訪問一個 Kotlin 掛起函數(shù) getUserInfo(),會看到 getUserInfo() 的類型是 (Continuation)-> Object,接收 Continuation 為參數(shù),返回值是 Object。而在這里,函數(shù)簽名的變化可以分為兩個部分:函數(shù)簽名的變化可以分為兩個部分:函數(shù)參數(shù)的變化和函數(shù)返回值的變化。

1.CPS 參數(shù)變化

suspend() 變成 (Continuation)

suspend fun getUserInfoContent(): String {
    withContext(Dispatchers.IO) {
        delay(1000L)
    }
    return "UserInfo"
}
suspend fun getFriendListContent(user: String): String {
    withContext(Dispatchers.IO) {
        delay(1000L)
    }
    return "Friend1, Friend2"
}
suspend fun getFeedListContent(user: String, list: String): String {
    withContext(Dispatchers.IO) {
        delay(1000L)
    }
    return "{FeddList...}"
}
suspend fun fetchContent() {
    val userInfoContent = getUserInfoContent()
    val friendListContent = getFriendListContent(userInfoContent)
    val feedListContent = getFeedListContent(userInfoContent, friendListContent)
}

上述代碼轉(zhuǎn)換成java代碼如下:

public final class TestCoroutionKt {
   @Nullable
   public static final Object getUserInfoContent(@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 TestCoroutionKt.getUserInfoContent(this);
            }
         };
      }
      Object $result = ((<undefinedtype>)$continuation).result;
      Object var3 = 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 var2 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
               switch(this.label) {
               case 0:
                  ResultKt.throwOnFailure($result);
                  this.label = 1;
                  if (DelayKt.delay(1000L, this) == var2) {
                     return var2;
                  }
                  break;
               case 1:
                  ResultKt.throwOnFailure($result);
                  break;
               default:
                  throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
               }
               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) == var3) {
            return var3;
         }
         break;
      case 1:
         ResultKt.throwOnFailure($result);
         break;
      default:
         throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
      }
      return "UserInfo";
   }
   @Nullable
   public static final Object getFriendListContent(@NotNull String var0, @NotNull Continuation var1) {
      Object $continuation;
      label20: {
         if (var1 instanceof <undefinedtype>) {
            $continuation = (<undefinedtype>)var1;
            if ((((<undefinedtype>)$continuation).label & Integer.MIN_VALUE) != 0) {
               ((<undefinedtype>)$continuation).label -= Integer.MIN_VALUE;
               break label20;
            }
         }
         $continuation = new ContinuationImpl(var1) {
            // $FF: synthetic field
            Object result;
            int label;
            @Nullable
            public final Object invokeSuspend(@NotNull Object $result) {
               this.result = $result;
               this.label |= Integer.MIN_VALUE;
               return TestCoroutionKt.getFriendListContent((String)null, 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 var2 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
               switch(this.label) {
               case 0:
                  ResultKt.throwOnFailure($result);
                  this.label = 1;
                  if (DelayKt.delay(1000L, this) == var2) {
                     return var2;
                  }
                  break;
               case 1:
                  ResultKt.throwOnFailure($result);
                  break;
               default:
                  throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
               }
               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");
      }
      return "Friend1, Friend2";
   }
   @Nullable
   public static final Object getFeedListContent(@NotNull String var0, @NotNull String var1, @NotNull Continuation var2) {
      Object $continuation;
      label20: {
         if (var2 instanceof <undefinedtype>) {
            $continuation = (<undefinedtype>)var2;
            if ((((<undefinedtype>)$continuation).label & Integer.MIN_VALUE) != 0) {
               ((<undefinedtype>)$continuation).label -= Integer.MIN_VALUE;
               break label20;
            }
         }
         $continuation = new ContinuationImpl(var2) {
            // $FF: synthetic field
            Object result;
            int label;
            @Nullable
            public final Object invokeSuspend(@NotNull Object $result) {
               this.result = $result;
               this.label |= Integer.MIN_VALUE;
               return TestCoroutionKt.getFeedListContent((String)null, (String)null, this);
            }
         };
      }
      Object $result = ((<undefinedtype>)$continuation).result;
      Object var5 = 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 var2 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
               switch(this.label) {
               case 0:
                  ResultKt.throwOnFailure($result);
                  this.label = 1;
                  if (DelayKt.delay(1000L, this) == var2) {
                     return var2;
                  }
                  break;
               case 1:
                  ResultKt.throwOnFailure($result);
                  break;
               default:
                  throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
               }
               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) == var5) {
            return var5;
         }
         break;
      case 1:
         ResultKt.throwOnFailure($result);
         break;
      default:
         throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
      }
      return "{FeddList...}";
   }
   @Nullable
   public static final Object fetchContent(@NotNull Continuation var0) {
      Object $continuation;
      label37: {
         if (var0 instanceof <undefinedtype>) {
            $continuation = (<undefinedtype>)var0;
            if ((((<undefinedtype>)$continuation).label & Integer.MIN_VALUE) != 0) {
               ((<undefinedtype>)$continuation).label -= Integer.MIN_VALUE;
               break label37;
            }
         }
         $continuation = new ContinuationImpl(var0) {
            // $FF: synthetic field
            Object result;
            int label;
            Object L$0;
            @Nullable
            public final Object invokeSuspend(@NotNull Object $result) {
               this.result = $result;
               this.label |= Integer.MIN_VALUE;
               return TestCoroutionKt.fetchContent(this);
            }
         };
      }
      Object var10000;
      label31: {
         String userInfoContent;
         Object var6;
         label30: {
            Object $result = ((<undefinedtype>)$continuation).result;
            var6 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
            switch(((<undefinedtype>)$continuation).label) {
            case 0:
               ResultKt.throwOnFailure($result);
               ((<undefinedtype>)$continuation).label = 1;
               var10000 = getUserInfoContent((Continuation)$continuation);
               if (var10000 == var6) {
                  return var6;
               }
               break;
            case 1:
               ResultKt.throwOnFailure($result);
               var10000 = $result;
               break;
            case 2:
               userInfoContent = (String)((<undefinedtype>)$continuation).L$0;
               ResultKt.throwOnFailure($result);
               var10000 = $result;
               break label30;
            case 3:
               ResultKt.throwOnFailure($result);
               var10000 = $result;
               break label31;
            default:
               throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
            }
            userInfoContent = (String)var10000;
            ((<undefinedtype>)$continuation).L$0 = userInfoContent;
            ((<undefinedtype>)$continuation).label = 2;
            var10000 = getFriendListContent(userInfoContent, (Continuation)$continuation);
            if (var10000 == var6) {
               return var6;
            }
         }
         String friendListContent = (String)var10000;
         ((<undefinedtype>)$continuation).L$0 = null;
         ((<undefinedtype>)$continuation).label = 3;
         var10000 = getFeedListContent(userInfoContent, friendListContent, (Continuation)$continuation);
         if (var10000 == var6) {
            return var6;
         }
      }
      String var3 = (String)var10000;
      return Unit.INSTANCE;
   }
}

每一次函數(shù)調(diào)用的時候,continuation 都會作為最后一個參數(shù)傳到掛起函數(shù)里,Kotlin 編譯器幫我們做的,我們開發(fā)者是無感知。

2.CPS 返回值變化

final Object getUserInfoContent(@NotNull Continuation var0)
final Object getFriendListContent(@NotNull String var0, @NotNull Continuation var1)
final Object getFeedListContent(@NotNull String var0, @NotNull String var1, @NotNull Continuation var2)
suspend fun getUserInfoContent(): String {}
fun getUserInfoContent(cont: Continuation): Any? {}

經(jīng)過 CPS 轉(zhuǎn)換后,完整的函數(shù)簽名如下:

suspend fun getUserInfoContent(): String {}
fun getUserInfoContent(cont: Continuation<String>): Any? {}

Kotlin 編譯器的 CPS 轉(zhuǎn)換是等價的轉(zhuǎn)換。suspend () -> String 轉(zhuǎn)換成 (Continuation) -> Any?。

掛起函數(shù)經(jīng)過 CPS 轉(zhuǎn)換后,它的返回值有一個重要作用:標(biāo)志該掛起函數(shù)有沒有被掛起。

其實掛起函數(shù)也能不被掛起。

首先只要有 suspend 修飾的函數(shù),它就是掛起函數(shù)。

suspend fun getUserInfoContent(): String {
    withContext(Dispatchers.IO) {
        delay(1000L)
    }
    return "UserInfo"
}

執(zhí)行到 withContext{} 的時候,就會返回 CoroutineSingletons.COROUTINE_SUSPENDED 表示函數(shù)被掛起了。

下面的函數(shù)則是偽掛起函數(shù)

suspend fun getUserInfoContent2(): String {
    return "UserInfo"
}

因為它的方法體跟普通函數(shù)一樣。它跟一般的掛起函數(shù)有個區(qū)別:在執(zhí)行的時候,它并不會被掛起,因為它就是個普通函數(shù)。

二、掛起函數(shù)的反編譯

 @Nullable
   public static final Object fetchContent(@NotNull Continuation var0) {
      Object $continuation;
      label37: {
         if (var0 instanceof <undefinedtype>) {
            $continuation = (<undefinedtype>)var0;
            if ((((<undefinedtype>)$continuation).label & Integer.MIN_VALUE) != 0) {
               ((<undefinedtype>)$continuation).label -= Integer.MIN_VALUE;
               break label37;
            }
         }
         $continuation = new ContinuationImpl(var0) {
            // $FF: synthetic field
            Object result;
            int label;
            Object L$0;
            @Nullable
            public final Object invokeSuspend(@NotNull Object $result) {
               this.result = $result;
               this.label |= Integer.MIN_VALUE;
               return TestCoroutionKt.fetchContent(this);
            }
         };
      }
      Object var10000;
      label31: {
         String userInfoContent;
         Object var6;
         label30: {
            Object $result = ((<undefinedtype>)$continuation).result;
            var6 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
            switch(((<undefinedtype>)$continuation).label) {
            case 0:
               ResultKt.throwOnFailure($result);
               ((<undefinedtype>)$continuation).label = 1;
               var10000 = getUserInfoContent((Continuation)$continuation);
               if (var10000 == var6) {
                  return var6;
               }
               break;
            case 1:
               ResultKt.throwOnFailure($result);
               var10000 = $result;
               break;
            case 2:
               userInfoContent = (String)((<undefinedtype>)$continuation).L$0;
               ResultKt.throwOnFailure($result);
               var10000 = $result;
               break label30;
            case 3:
               ResultKt.throwOnFailure($result);
               var10000 = $result;
               break label31;
            default:
               throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
            }
            userInfoContent = (String)var10000;
            ((<undefinedtype>)$continuation).L$0 = userInfoContent;
            ((<undefinedtype>)$continuation).label = 2;
            var10000 = getFriendListContent(userInfoContent, (Continuation)$continuation);
            if (var10000 == var6) {
               return var6;
            }
         }
         String friendListContent = (String)var10000;
         ((<undefinedtype>)$continuation).L$0 = null;
         ((<undefinedtype>)$continuation).label = 3;
         var10000 = getFeedListContent(userInfoContent, friendListContent, (Continuation)$continuation);
         if (var10000 == var6) {
            return var6;
         }
      }
      String var3 = (String)var10000;
      return Unit.INSTANCE;
   }

label 是用來代表協(xié)程狀態(tài)機(jī)當(dāng)中狀態(tài);

result 是用來存儲當(dāng)前掛起函數(shù)執(zhí)行結(jié)果;

invokeSuspend 這個函數(shù),是整個狀態(tài)機(jī)的入口,它會將執(zhí)行流程轉(zhuǎn)交給 fetchContent 進(jìn)行再次調(diào)用;

userInfoContent, friendListContent用來存儲歷史掛起函數(shù)執(zhí)行結(jié)果。

if (var0 instanceof <undefinedtype>) {
            $continuation = (<undefinedtype>)var0;
            if ((((<undefinedtype>)$continuation).label & Integer.MIN_VALUE) != 0) {
               ((<undefinedtype>)$continuation).label -= Integer.MIN_VALUE;
               break label37;
            }
         }
  $continuation = new ContinuationImpl(var0) {
            // $FF: synthetic field
            Object result;
            int label;
            Object L$0;
            @Nullable
            public final Object invokeSuspend(@NotNull Object $result) {
               this.result = $result;
               this.label |= Integer.MIN_VALUE;
               return TestCoroutionKt.fetchContent(this);
            }
         };

invokeSuspend 最終會調(diào)用 fetchContent;

如果是初次運行,會創(chuàng)建一個 ContinuationImpl對象,completion 作為參數(shù);這相當(dāng)于用一個新的 Continuation 包裝了舊的 Continuation;

如果不是初次運行,直接將 completion 賦值給 continuation;這說明 continuation 在整個運行期間,只會產(chǎn)生一個實例,這能極大地節(jié)省內(nèi)存開銷(對比 CallBack)。

// result 接收協(xié)程的運行結(jié)果
var result = continuation.result
// suspendReturn 接收掛起函數(shù)的返回值
var suspendReturn: Any? = null
// CoroutineSingletons 是個枚舉類
// COROUTINE_SUSPENDED 代表當(dāng)前函數(shù)被掛起了
val sFlag = CoroutineSingletons.COROUTINE_SUSPENDED

continuation.label 是狀態(tài)流轉(zhuǎn)的關(guān)鍵,continuation.label 改變一次,就代表了掛起函數(shù)被調(diào)用了一次;每次掛起函數(shù)執(zhí)行完后,都會檢查是否發(fā)生異常;

fetchContent 里的原本的代碼,被拆分到狀態(tài)機(jī)里各個狀態(tài)中,分開執(zhí)行;getUserInfoContent(continuation)、getFriendListContent(user, continuation)、getFeedListContent(friendList, continuation) 三個函數(shù)調(diào)用的是同一個 continuation 實例;

var6 = IntrinsicsKt.getCOROUTINE_SUSPENDED();

如果一個函數(shù)被掛起了,它的返回值會是 CoroutineSingletons.COROUTINE_SUSPENDED;

在掛起函數(shù)執(zhí)行的過程中,狀態(tài)機(jī)會把之前的結(jié)果以成員變量的方式保存在 continuation 中。

本質(zhì)上來說,Kotlin 協(xié)程就是通過 label 代碼段嵌套,配合 switch 巧妙構(gòu)造出一個狀態(tài)機(jī)結(jié)構(gòu)。

三、Continuation

public interface Continuation<in T> {
    public val context: CoroutineContext
    public fun resumeWith(result: Result<T>)
}
@Suppress("WRONG_MODIFIER_TARGET")
public suspend inline val coroutineContext: CoroutineContext
    get() {
        throw NotImplementedError("Implemented as intrinsic")
    }

注意上面的suspend inline val coroutineContext,suspend 的這種用法只是一種特殊用法。它的作用:它是一個只有在掛起函數(shù)作用域下,才能訪問的頂層的不可變的變量。這里的 inline,意味著它的具體實現(xiàn)會被直接復(fù)制到代碼的調(diào)用處。

suspend fun testContext() = coroutineContext
@Nullable
   public static final Object testContext(@NotNull Continuation $completion) {
      return $completion.getContext();
   }

“suspend inline val coroutineContext”,本質(zhì)上就是 Kotlin 官方提供的一種方便開發(fā)者在掛起函數(shù)當(dāng)中,獲取協(xié)程上下文的手段。它的具體實現(xiàn),其實是 Kotlin 編譯器來完成的。

我們在掛起函數(shù)當(dāng)中無法直接訪問 Continuation 對象,但可以訪問到 Continuation 當(dāng)中的 coroutineContext。要知道,正常情況下,我們想要訪問 Continuation.coroutineContext,首先是要拿到 Continuation 對象的。但是,Kotlin 官方通過“suspend inline val coroutineContext”這個頂層變量,讓我們開發(fā)者能直接拿到 coroutineContext,卻對 Continuation 毫無感知。

掛起函數(shù)與 CoroutineContext 確實有著緊密的聯(lián)系。每個掛起函數(shù)當(dāng)中都會有 Continuation,而每個 Continuation 當(dāng)中都會有 coroutineContext。并且,我們在掛起函數(shù)當(dāng)中,就可以直接訪問當(dāng)前的 coroutineContext。

到此這篇關(guān)于Kotlin掛起函數(shù)應(yīng)用介紹的文章就介紹到這了,更多相關(guān)Kotlin掛起函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android拖拽助手ViewDragHelper的創(chuàng)建與使用實例

    Android拖拽助手ViewDragHelper的創(chuàng)建與使用實例

    ViewDragHelper是針對 ViewGroup 中的拖拽和重新定位 views 操作時提供了一系列非常有用的方法和狀態(tài)追蹤,下面這篇文章主要給大家介紹了關(guān)于Android拖拽助手ViewDragHelper的創(chuàng)建與使用的相關(guān)資料,需要的朋友可以參考下
    2022-05-05
  • Flutter狀態(tài)管理Bloc使用示例詳解

    Flutter狀態(tài)管理Bloc使用示例詳解

    這篇文章主要為大家介紹了Flutter狀態(tài)管理Bloc使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • 最新評論