源码分析-Kotlin中协程的挂起和恢复

84aa230f3181b62522c62c8ebbfddaf7.png

0b9947f226ad96daf5b8739158a67837.gif

本文字数:12447

预计阅读时间:32分钟

源码分析-Kotlin中协程的挂起和恢复

前言

Kotlin中的协程经过几个版本的升级已经非常成熟了,但是协程的概念目前没有一个明确且被普遍接受的定义。究其根源无论我们怎么去理解协程的概念,它最核心的点就是函数或者一段程序能够被挂起,稍后再挂起的位置恢复。所以在任何场景下探讨协程都能够落脚到挂起和恢复。本文通过源码对协程创建->挂起->恢复流程进行分析解读。希望能够帮助大家对Kotlin协程的理解起到帮助。

协程的创建

Kotlin中协程是复合协程,是为了方便开发者使用而进一步封装的API,当我们在分析的时候无从下手就是因为经过封装的协程在经过编译后才能看到它的庐山真面目。下面我们通过构造一个简单的协程并反编译成java代码查看。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        startCoroutine()
    }

    private fun startCoroutine() {
        val coroutine: suspend CoroutineScope.() -> Unit = {
            cumpute1()
            cumpute2()
        }
        GlobalScope.launch(block = coroutine)
    }

    suspend fun cumpute1() {
        print("cupmpute1")
    }

    suspend fun cumpute2() {
        print("cupmpute1")
    }
}

coroutine 属性是 suspend CoroutineScope.() -> Unit 函数类型对象,反编译成java代码

final class MainActivity$startCoroutine$coroutine$1 extends SuspendLambda implements Function2 {
  //状态机初始值0
 int label;

 public final Object invokeSuspend(Object $result) {
    Object coroutine_suspend = IntrinsicsKt.getCOROUTINE_SUSPENDED();
    switch(this.label) {
    case 0:
       ...
       //将label置为1 开始调用挂起函数cumpute1
       this.label = 1;
       if (MainActivity.this.cumpute1(this) == coroutine_suspend) {
          //如果函数被挂起返回挂起标识
          return coroutine_suspend;
       }
       break;
       ...
    }

    //将label置为2 开始调用挂起函数cumpute2
    this.label = 2;
    if (MainActivity.this.cumpute2(this) == coroutine_suspend) {
       return coroutine_suspend;
    } else {
       return Unit.INSTANCE;
    }
 }

 public final Continuation create(Object value,Continuation completion) {
    ...
    //创建并返回一个Continuation对象
    MainActivity$startCoroutine$coroutine$1 coroutine = new  
    MainActivity$startCoroutine$coroutine$1(completion);
    return coroutine;
 }

 public final Object invoke(Object var1, Object var2) {
    return ((MainActivity$startCoroutine$coroutine$1)this.create(var1,  (Continuation)var2)).invokeSuspend(Unit.INSTANCE);
 }

}

通过反编译代码可以看到声明的 coroutine 转换成了继承 SuspendLambda 的类,可以称之为协程体类。内部实现了两个方法

  • invokeSuspend() 内部是通过label状态来控制调用流程.

  • create()方法接收一个 Continuation 对象,然后创建并返回协程体类对象。

public final Object cumpute1(Continuation completion) {
    ...
    return Unit.INSTANCE;
 }

suspend 修饰的函数经过反编译后额外接收了一个 Continuation 类型参数,这也就是为什么普通函数内不能调用 suspend 修饰的函数的原因。附上 SuspendLambda 的类图

6b4a460602d97be00e394b5998afa845.png

从类图上可以看出该类的承链 SuspendLambda -> ContinuationImpl -> BaseContinuationImpl -> Continuation

  • Continuation 是一个接口定义了 resumeWith(result:Result) 方法 和 CoroutineContext 上下文属性

  • BaseContinuationImpl 是一个抽象类实现了 resumeWith( result : Result ) 方法 ,并声明抽象方法 invokeSuspend()create() 方法。

  • ContinuationImpl 继承 BaseContinuationImpl  构造方法接收 Continuation 类型参数,内部实现 intercepted() 方法将原始协程体类对象拦截包装,添加调度器实现并返回新的协程体类对象 DispatchedContinuation

协程的挂起

接上面创建的协程代码,以 launch() 函数作为入口开始分析协程是如何挂起的。launch() 函数是 CoroutineScope 的一个扩展实现

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineSta
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值