协程 - 挂起和恢复

相关链接

协程是什么

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

协程能做什么

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

和线程有什么区别,看扔物线的课程说,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 来实现的

相关推荐
闲暇部落35 分钟前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
长亭外的少年16 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
JIAY_WX16 小时前
kotlin
开发语言·kotlin
麦田里的守望者江1 天前
KMP 中的 expect 和 actual 声明
android·ios·kotlin
菠菠萝宝1 天前
【YOLOv8】安卓端部署-1-项目介绍
android·java·c++·yolo·目标检测·目标跟踪·kotlin
恋猫de小郭1 天前
Kotlin Multiplatform 未来将采用基于 JetBrains Fleet 定制的独立 IDE
开发语言·ide·kotlin
枫__________2 天前
kotlin 协程 job的cancel与cancelAndJoin区别
android·开发语言·kotlin
鸠摩智首席音效师2 天前
如何在 Ubuntu 上配置 Kotlin 应用环境 ?
linux·ubuntu·kotlin
jikuaidi6yuan4 天前
Java与Kotlin在鸿蒙中的地位
java·kotlin·harmonyos
liulanba4 天前
Kotlin的data class
前端·微信·kotlin