IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> kotlin协程原理 -> 正文阅读

[移动开发]kotlin协程原理

kotlin的协程包括基础设施部分和在基础设施上封装的库。主要看下自己如何使用基础设施部分以及它的原理。

首先看下我们如何使用的。

1.创建协程。

fun <T> launch(block : suspend () -> T){
    val continuation = block.createCoroutine(object : Continuation<T> {
        override val context: CoroutineContext = EmptyCoroutineContext

        override fun resumeWith(result: Result<T>) {
            println(result.getOrNull().toString())
        }
    })
    continuation.resume(Unit)
}

传入一个挂起函数通过createCoroutine方法传入一个Continuation对象创建协程。

然后是我们的挂起函数。

suspend fun loadData() = suspendCoroutine<String> {
    it.resume("abcd")
}

我们平时写挂起函数的时候并不这么写,这么写主要是因为我们要拿到传入的Continuation对象,就是it.

然后就是使用。

fun main(){
    launch {
        val loadImg = loadData()
        println("img = $loadImg")
    }
}

代理本身没有什么意义。我们将这些代码反编译一下。首先是launch部分。

public static final void launch(@NotNull Function1 block) {
      Intrinsics.checkNotNullParameter(block, "block");
      Continuation coroutine = ContinuationKt.createCoroutine(block, (Continuation)(new Continuation() {
         @NotNull
         private final CoroutineContext context;

         @NotNull
         public CoroutineContext getContext() {
            return this.context;
         }

         public void resumeWith(@NotNull Object result) {
            boolean var3 = false;
            String var2 = String.valueOf(Result.isFailure-impl(result) ? null : result);
            var3 = false;
            System.out.println(var2);
         }

         {
            this.context = (CoroutineContext)EmptyCoroutineContext.INSTANCE;
         }
      }));
      Unit var3 = Unit.INSTANCE;
      boolean var4 = false;
      Companion var5 = Result.Companion;
      boolean var6 = false;
      coroutine.resumeWith(Result.constructor-impl(var3));
   }

然后是挂起函数部分

public static final Object loadImg(@NotNull Continuation $completion) {
      boolean var1 = false;
      boolean var2 = false;
      boolean var3 = false;
      SafeContinuation var4 = new SafeContinuation(IntrinsicsKt.intercepted($completion));
      Continuation it = (Continuation)var4;
      int var6 = false;
      String var8 = "abcd";
      boolean var9 = false;
      Companion var10 = Result.Companion;
      boolean var11 = false;
      it.resumeWith(Result.constructor-impl(var8));
      Object var10000 = var4.getOrThrow();
      if (var10000 == IntrinsicsKt.getCOROUTINE_SUSPENDED()) {
         DebugProbesKt.probeCoroutineSuspended($completion);
      }

      return var10000;
   }

最后是我们使用的。

public static final void main() {
      launch((Function1)(new Function1((Continuation)null) {
         int label;

         @Nullable
         public final Object invokeSuspend(@NotNull Object $result) {
            Object var5 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
            Object var10000;
            switch(this.label) {
            case 0:
               ResultKt.throwOnFailure($result);
               this.label = 1;
               var10000 = MainKt.loadImg(this);
               if (var10000 == var5) {
                  return var5;
               }
               break;
            case 1:
               ResultKt.throwOnFailure($result);
               var10000 = $result;
               break;
            default:
               throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
            }

            String loadImg = (String)var10000;
            String var3 = "img = " + loadImg;
            boolean var4 = false;
            System.out.println(var3);
            return Unit.INSTANCE;
         }

         @NotNull
         public final Continuation create(@NotNull Continuation completion) {
            Intrinsics.checkNotNullParameter(completion, "completion");
            Function1 var2 = new <anonymous constructor>(completion);
            return var2;
         }

         public final Object invoke(Object var1) {
            return ((<undefinedtype>)this.create((Continuation)var1)).invokeSuspend(Unit.INSTANCE);
         }
      }));
   }

这里面看着有点奇怪,不明白怎么反编译成这个样子。其实,launch传入的block会被编译成一个类。这个类继承自SuspendLambda实现了Function1接口。我们简单看下。

internal abstract class SuspendLambda(
    public override val arity: Int,
    completion: Continuation<Any?>?
) : ContinuationImpl(completion), FunctionBase<Any?>, SuspendFunction {
    constructor(arity: Int) : this(arity, null)

    public override fun toString(): String =
        if (completion == null)
            Reflection.renderLambdaToString(this) // this is lambda
        else
            super.toString() // this is continuation
}

internal abstract class ContinuationImpl(
    completion: Continuation<Any?>?,
    private val _context: CoroutineContext?
) : BaseContinuationImpl(completion) {...}

internal abstract class BaseContinuationImpl(
    // This is `public val` so that it is private on JVM and cannot be modified by untrusted code, yet
    // it has a public getter (since even untrusted code is allowed to inspect its call stack).
    public val completion: Continuation<Any?>?
) : Continuation<Any?>, CoroutineStackFrame, Serializable {
    // This implementation is final. This fact is used to unroll resumeWith recursion.
    public final override fun resumeWith(result: Result<Any?>) {
        // This loop unrolls recursion in current.resumeWith(param) to make saner and shorter stack traces on resume
        var current = this
        var param = result
        while (true) {
            // Invoke "resume" debug probe on every resumed continuation, so that a debugging library infrastructure
            // can precisely track what part of suspended callstack was already resumed
            probeCoroutineResumed(current)
            with(current) {
                val completion = completion!! // fail fast when trying to resume continuation without completion
                val outcome: Result<Any?> =
                    try {
                        val outcome = invokeSuspend(param)
                        if (outcome === COROUTINE_SUSPENDED) return
                        Result.success(outcome)
                    } catch (exception: Throwable) {
                        Result.failure(exception)
                    }
                releaseIntercepted() // this state machine instance is terminating
                if (completion is BaseContinuationImpl) {
                    // unrolling recursion via loop
                    current = completion
                    param = outcome
                } else {
                    // top-level completion reached -- invoke and return
                    completion.resumeWith(outcome)
                    return
                }
            }
        }
    }

    protected abstract fun invokeSuspend(result: Result<Any?>): Any?

    protected open fun releaseIntercepted() {
        // does nothing here, overridden in ContinuationImpl
    }

    public open fun create(completion: Continuation<*>): Continuation<Unit> {
        throw UnsupportedOperationException("create(Continuation) has not been overridden")
    }

    public open fun create(value: Any?, completion: Continuation<*>): Continuation<Unit> {
        throw UnsupportedOperationException("create(Any?;Continuation) has not been overridden")
    }

    public override fun toString(): String =
        "Continuation at ${getStackTraceElement() ?: this::class.java.name}"

    // --- CoroutineStackFrame implementation

    public override val callerFrame: CoroutineStackFrame?
        get() = completion as? CoroutineStackFrame

    public override fun getStackTraceElement(): StackTraceElement? =
        getStackTraceElementImpl()
}

SuspendLambda又继承了ContinuationImpl抽象类,ContinuationImpl又继承自BaseContinuationImpl类。我们先留意下BaseContinuationImpl中的resumeWith方法并且又invokeSuspend的抽象方法。再回头看下生成的类是不是就实现了invokeSuspend方法。

可以看到当创建协程的时候调用了ContinuationKt.createCoroutine方法。

public fun <T> (suspend () -> T).createCoroutine(
    completion: Continuation<T>
): Continuation<Unit> =
    SafeContinuation(createCoroutineUnintercepted(completion).intercepted(), COROUTINE_SUSPENDED)

public actual fun <T> (suspend () -> T).createCoroutineUnintercepted(
    completion: Continuation<T>
): Continuation<Unit> {
    val probeCompletion = probeCoroutineCreated(completion)
    return if (this is BaseContinuationImpl)
        create(probeCompletion)
    else
        createCoroutineFromSuspendFunction(probeCompletion) {
            (this as Function1<Continuation<T>, Any?>).invoke(it)
        }
}

可以看到createCoroutine调用到了createCoroutineUnintercepted方法。在该方法中判断了this is BaseContinuationImpl.因为这两个方法本就是suspend () -> T的扩展方法。

那么现在传入到launch中的就是生成的继承自SuspendLambda的那个类的对象。上面我们看了该类就是间接的继承自BaseContinuationImpl,因此回调用到该类的create方法。该类的create方法做了什么呢就是将我们创建的匿名的Continuation对象传入生成一个新的对象并返回。

然后当使用返回的Continuation对象调用其resume方法的时候,其实是调用到了它的resumeWith方法。如下。

public inline fun <T> Continuation<T>.resume(value: T): Unit =
    resumeWith(Result.success(value))

resumeWith方法在哪儿呢,前面提到了,就在BaseContinuationImpl里面。会调用到重写的invokeSuspend方法。第一次进入的时候lable为0,走第一个case,lable赋值为1,调用到loadImg方法,loadImg这个挂起函数真正挂起的话getOrThrow方法会立刻返回COROUTINE_SUSPENDED,标记挂起了。var5也就是COROUTINE_SUSPENDED,然后就会返回到BaseContinuationImpl中的resumeWith中。if (outcome === COROUTINE_SUSPENDED) return就跳出循环。

然后如果过了一段时间挂起函数执行完了。就会调用Continuation对象(这个其实就是生成的继承自Suspendlambda的类)的resume或者resumeWith方法,最终还是调用到BaseContinuationImpl的resumeWith,并将结果传进去,然后是生成的类的invokeSuspend方法。现在lable已经变成1了,就会走case 1.就能拿到挂起函数执行的结果了。并赋值打印。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-03 11:19:29  更:2021-08-03 11:20:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 4:08:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码