• Kotlin挂起函数整理-基础


    1.Kotlin 协程的优势

    • 解决回调地狱的问题。
    • 以同步的方式完成异步任务。

    示例:

    1. fun main() {
    2. runBlocking {
    3. val a = getA()
    4. println(a)
    5. val b = getB(a)
    6. println(b)
    7. val c = getC(b)
    8. println(c)
    9. }
    10. }
    11. suspend fun getA(): String {
    12. withContext(Dispatchers.IO) {
    13. delay(2000L)
    14. }
    15. return "A content"
    16. }
    17. suspend fun getB(a: String): String {
    18. withContext(Dispatchers.IO) {
    19. delay(2000L)
    20. }
    21. return "$a B content"
    22. }
    23. suspend fun getC(b: String): String {
    24. withContext(Dispatchers.IO) {
    25. delay(2000L)
    26. }
    27. return "$b C content"
    28. }
    29. 输出
    30. A content
    31. A content B content
    32. A content B content C content

    suspend关键字修饰的方法 就是 挂起函数。挂起函数具备挂起和恢复的能力。挂起就是将程序执行流程转移到其他线程,主线程不阻塞。挂起函数的本质是Callback。

    Kotlin编译器检测到suspend关键字修饰的函数,会将挂起函数转换成带有CallBack的函数。

    1. suspend fun getA(): String {
    2. withContext(Dispatchers.IO) {
    3. delay(5000L)
    4. println("now in A process:" + Thread.currentThread())
    5. }
    6. /**
    7. * 这里的代码涉及挂起函数中的操作。
    8. */
    9. println("finish A process:" + Thread.currentThread())
    10. return "A content"
    11. }

     将上述Kotlin代码转换成java代码。

    1. @Nullable
    2. public static final Object getA(@NotNull Continuation var0) {
    3. Object $continuation;
    4. label20: {
    5. if (var0 instanceof ) {
    6. $continuation = ()var0;
    7. if (((()$continuation).label & Integer.MIN_VALUE) != 0) {
    8. (()$continuation).label -= Integer.MIN_VALUE;
    9. break label20;
    10. }
    11. }
    12. $continuation = new ContinuationImpl(var0) {
    13. // $FF: synthetic field
    14. Object result;
    15. int label;
    16. @Nullable
    17. public final Object invokeSuspend(@NotNull Object $result) {
    18. this.result = $result;
    19. this.label |= Integer.MIN_VALUE;
    20. return TestCoroutinue2Kt.getA(this);
    21. }
    22. };
    23. }
    24. Object $result = (()$continuation).result;
    25. Object var4 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
    26. switch((()$continuation).label) {
    27. case 0:
    28. ResultKt.throwOnFailure($result);
    29. CoroutineContext var10000 = (CoroutineContext)Dispatchers.getIO();
    30. Function2 var10001 = (Function2)(new Function2((Continuation)null) {
    31. int label;
    32. @Nullable
    33. public final Object invokeSuspend(@NotNull Object $result) {
    34. Object var3 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
    35. switch(this.label) {
    36. case 0:
    37. ResultKt.throwOnFailure($result);
    38. this.label = 1;
    39. if (DelayKt.delay(5000L, this) == var3) {
    40. return var3;
    41. }
    42. break;
    43. case 1:
    44. ResultKt.throwOnFailure($result);
    45. break;
    46. default:
    47. throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
    48. }
    49. String var2 = "now in A process:" + Thread.currentThread();
    50. System.out.println(var2);
    51. return Unit.INSTANCE;
    52. }
    53. @NotNull
    54. public final Continuation create(@Nullable Object value, @NotNull Continuation completion) {
    55. Intrinsics.checkNotNullParameter(completion, "completion");
    56. Function2 var3 = new (completion);
    57. return var3;
    58. }
    59. public final Object invoke(Object var1, Object var2) {
    60. return (()this.create(var1, (Continuation)var2)).invokeSuspend(Unit.INSTANCE);
    61. }
    62. });
    63. (()$continuation).label = 1;
    64. if (BuildersKt.withContext(var10000, var10001, (Continuation)$continuation) == var4) {
    65. return var4;
    66. }
    67. break;
    68. case 1:
    69. ResultKt.throwOnFailure($result);
    70. break;
    71. default:
    72. throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
    73. }
    74. String var1 = "finish A process:" + Thread.currentThread();
    75. System.out.println(var1);
    76. return "A content";
    77. }

    注意:runBlocking 的第二个参数 也是 传入一个 suspend修饰的函数 即挂起函数。

    public actual fun  runBlocking(context: CoroutineContext, block: suspend CoroutineScope.() -> T): T {

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

    1. /**
    2. * Interface representing a continuation after a suspension point that returns a value of type `T`.
    3. */
    4. @SinceKotlin("1.3")
    5. public interface Continuation<in T> {
    6. /**
    7. * The context of the coroutine that corresponds to this continuation.
    8. */
    9. public val context: CoroutineContext
    10. /**
    11. * Resumes the execution of the corresponding coroutine passing a successful or failed [result] as the
    12. * return value of the last suspension point.
    13. */
    14. public fun resumeWith(result: Result<T>)
    15. }

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

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

    1. fun main() {
    2. doA() //这里会报错
    3. }
    4. suspend fun doA() {
    5. }
    1. public static final void main() {
    2. }
    3. // $FF: synthetic method
    4. public static void main(String[] var0) {
    5. main();
    6. }
    1. @Nullable
    2. public static final Object doA(@NotNull Continuation $completion) {
    3. return Unit.INSTANCE;
    4. }

    被调用的挂起函数需要传入一个Continuation, 没有被suspend修饰的函数是没有Continuation参数的,所以没法在普通函数中调用挂起函数,普通函数没有Continuation。

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

  • 相关阅读:
    JSP双语字典查询系统myeclipse开发sql数据库bs框架java编程web网页结构
    PCB材料简单介绍
    TensorFlow 的基本概念和使用场景
    【CKS】考试之 kube-bench CIS 基准测试
    【LVS】lvs的四种模式的区别是什么?
    【已解决】由于此设备上的安全设置已更改,你的pin不再可用,单击以重新设置Pin
    STM32Cube学习(1)——点灯&配置
    Camera-3A AE/AWB/AF
    三万字盘点Spring/Boot的那些常用扩展点
    日期格式化 YYYY-MM-DD 出现时间偏移量
  • 原文地址:https://blog.csdn.net/zhangying1994/article/details/126691885