协程 - 挂起和恢复

相关链接

协程是什么

并发设计模式,可以简化异步执行的代码

协程能做什么

协程可以用来执行异步任务

和线程有什么区别,看扔物线的课程说,kotlin 协程就是线程,而线程意味者 CPU 资源, cpu 的时间片

怎么使用

launch({ val user = api.getUser() // 👈 网络请求(IO 线程) nameTv.text = user.name // 👈 更新 UI(主线程) })

launch 函数加上实现在 {} 中具体的逻辑,就构成了一个协程。

  • 挂起函数是什么

    协程中的一种函数,在执行到 suspend 函数时,主线程暂停执行协程中的剩余代码

    那函数挂起以后呢,谁来执行呢? 由挂起函数指定,一般都需要指定子线程(IO),不然挂起没有意义

    也就是协程可以用来做异步任务并且不用写很多回调了

  • Suspend 修饰

    挂起函数的使用也有一些限制,比如只能在协程中或者其他挂起函数中使用

挂起和恢复

  • 挂起是函数的挂起,相当于 return
  • 恢复也是函数的恢复,相当于 callback

当使用 suspend 声明一个挂起函数时,有点类似注解,告诉编译器需要实现一些代码,从协程的源码中是很难了解到它的原理的,需要观察编译后的产物

示例查看的步骤:

kotlin 复制代码
suspend  fun  testCoroutine(){
    Log.e("打印","测试 delay 前")
    delay(2000)
    Log.e("打印","测试 delay后打印")
 }

编译后的结果

php 复制代码
   @Nullable
   public final Object testCoroutine(@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;
			// 唤醒 -  continuation 回调执行 invokeSuspend
			// 内部执行了我们的 testCoroutine() 
            @Nullable
            public final Object invokeSuspend(@NotNull Object $result) {
               this.result = $result;
               this.label |= Integer.MIN_VALUE;
               return MainActivity.this.testCoroutine(this);
            }
         };
      }

      Object $result = ((<undefinedtype>)$continuation).result;
      Object var4 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
      switch (((<undefinedtype>)$continuation).label) {
         case 0:
            ResultKt.throwOnFailure($result);
            Log.e("打印", "测试 delay 前");
            ((<undefinedtype>)$continuation).label = 1;
			// 这里挂起就是直接 return 了
			// var4 就是 COROUTINE_SUSPENDED
            if (DelayKt.delay(2000L, (Continuation)$continuation) == var4) {
               return var4;
            }
            break;
         case 1:
            ResultKt.throwOnFailure($result);
            break;
         default:
            throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
      }

      Log.e("打印", "测试 delay后打印");
      return Unit.INSTANCE;
   }

怎样改造原有代码

落到应用上,怎样使用协程来改造我们的旧项目代码呢?

  • 方式一
java 复制代码
/** 举例
** fun parseFile()
**/
lifecyclesScope.launch{
    val fileContent = lifecyclesScope.async{
        parseFile().await()
    }
    println(fileContent)
}

这种方式通过调用 await() 来等待方法执行结束,不过每次都要自行再包一层 async{},并且还要带要调用一下 await() 有点不太优雅

这里补充一下,async 会开启线程来执行任务,内部的线程池的核心线程数为 ==2== ,最大线程数为 ==cpu 核心数==

  • 方式二
kotlin 复制代码
    lifecyclesScope.launch{
    val fileContent = parseFile()
    println(fileContent)
    }

    /\*\*

    *   改造 parseFile 内部
        \*\*/
        suspend fun parseFile(){
        // 编译以后就会变成 CoroutineSuspended
        // 执行会挂起
        return suspendCanceableCoroutine{ continuation->
        Thread{
        //... io
        continuation.resumeWith(Result.success("xxxxx"))
        }.start()
        }
        }

    // 这种方式类似 delay() 的实现

    public suspend fun delay(timeMillis: Long) {
    if (timeMillis <= 0) return // don't delay
    return suspendCancellableCoroutine sc@ { cont: CancellableContinuation&lt;Unit&gt; ->
    // if timeMillis == Long.MAX\_VALUE then just wait forever like awaitCancellation,      		don't schedule.
    if (timeMillis < Long.MAX\_VALUE) {
    cont.context.delay.scheduleResumeAfterDelay(timeMillis, cont)
    }
    }
    }

这种方式是通过使用 suspendCancellableCoroutine 包裹我们原有的代码块,在执行完成后 resumeWith 返回结果

Retrofit 在 2.8 以后,通过扩展 Call 支持 await() ,内部也是用 suspendCancellableCoroutine 来实现的

相关推荐
xvch2 小时前
Kotlin 2.1.0 入门教程(二十三)泛型、泛型约束、协变、逆变、不变
android·kotlin
xvch2 天前
Kotlin 2.1.0 入门教程(二十四)泛型、泛型约束、绝对非空类型、下划线运算符
android·kotlin
zhangphil2 天前
Android Coil ImageLoader MemoryCache设置Key与复用内存缓存,Kotlin
android·kotlin
mmsx2 天前
kotlin Java 使用ArrayList.add() ,set()前面所有值被 覆盖 的问题
android·开发语言·kotlin
lavins2 天前
android studio kotlin项目build时候提示错误 Unknown Kotlin JVM target: 21
jvm·kotlin·android studio
面向未来_3 天前
JAVA Kotlin Androd 使用String.format()格式化日期
java·开发语言·kotlin
alexhilton3 天前
选择Retrofit还是Ktor:给Android开发者的指南
android·kotlin·android jetpack
GordonH19913 天前
Kotlin 优雅的接口实现
android·java·kotlin
wangz763 天前
Android 下用kotlin写一个sqlite
android·sqlite·kotlin·jetpack compose
yzpyzp4 天前
kotlin中RxHttp的toAwaitResponse和awaitResult函数的使用
android·kotlin