文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Kotlin挂起函数的详细介绍

2024-04-02 19:55

关注

Kotlin 协程的优势:

示例:

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关键字修饰的方法 就是 挂起函数。挂起函数具备挂起和恢复的能力。挂起就是将程序执行流程转移到其他线程,主线程不阻塞。挂起函数的本质是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 {

可以发现上面的Continuation 是一个带有泛型参数的Callback,这里的转换称为CPS转换,将原本的同步挂起函数转换成CallBack异步代码。


@SinceKotlin("1.3")
public interface Continuation<in T> {
    
    public val context: CoroutineContext
    
    public fun resumeWith(result: Result<T>)
}

注意:挂起函数,只能在协程中被调用,或者被其他挂起函数调用。

为什么挂起函数可以调用挂起函数,而普通函数不能调用挂起函数?

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。

挂起函数最终都是在协程中被调用,协程提供了挂起函数运行的环境。

到此这篇关于Kotlin挂起函数的详细介绍的文章就介绍到这了,更多相关Kotlin挂起函数内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯