【九月打卡】第1天 一课掌握Kotlin 突破开发语言瓶颈
2022/9/7 3:22:56
本文主要是介绍【九月打卡】第1天 一课掌握Kotlin 突破开发语言瓶颈,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
课程名称: 一课掌握Kotlin 突破开发语言瓶颈
课程章节: 协程初步 - Kotlin协程的基本要素(11-5,11-6)
课程讲师: bennyhuo
课程内容:
挂起函数
- 挂起函数就是用suspend修饰的函数
- 挂起函数只能在其他挂起函数或协程中调用
- 挂起函数调用时包含了协程“挂起”的语义
- 挂起函数返回时包含了协程“恢复”的语义
挂起函数的类型
suspend fun foo() {} ---- suspend () -> Unit suspend fun foo(a: Int): String {} ---- suspend (Int) -> String
跟函数类型一致,只是前面多了个suspend关键字修饰
挂起函数的本质
suspend修饰的挂起方法,通过Java反编译或者在Java上调用时,挂起函数会多了一个参数Continuation
fun foo(continuation: Continuation<Unit>): Any {} fun foo(a: Int, continuation: Continuation<String>): Any {}
- Continuation的泛型参数由suspend挂起函数的返回值决定
- 由于挂起函数实际上需要接收一个Continuation参数,所以挂起函数只能在其他挂起函数或协程中调用
- Any的返回值有两种情况:
- 当挂起函数里面没有真正的挂起,那么Any就是函数的返回值
- 当挂起函数里面真正的挂起,那么Any返回的是挂起标志对象(COROUTINE_SUSPEND)
什么是真正的挂起和没有真正的挂起?
真正的挂起就是必须异步调用resume
比如:
- 切换到其他线程resume
- 单线程事件循环异步执行
没有真正的挂起就是在suspendCoroutine中直接return,或者没有进行线程切换就执行resume
如何将一个回调函数转写成挂起函数
- 使用suspendCoroutine获取挂起函数的Continuation
- 回调成功的分支使用Continuation.resume(value)
- 回调失败则使用Continuation.resumeWithException(e)
协程的创建和启动
createCoroutine
createCoroutine是先创建出一个协程Continuation,然后在通过Continuation.resume启动协程
创建协程:
fun <T> (suspend () -> T).createCoroutine( completion: Continuation<T> ): Continuation<Unit> fun <R, T> (suspend R.() -> T).createCoroutine( receiver: R, completion: Continuation<T> ): Continuation<Unit>
创建协程涉及到两个Continuation:
- 一个作为createCoroutine的参数穿进去,给挂起函数执行完后调用
- 一个作为createCoroutine的返回值,作为该协程的句柄,用于启动协程
启动协程
调用resume(Unit)
suspend { ... }.createCoroutine(object: Continuation<Unit> { override val context = EmptyCoroutineContext override fun resumeWith(result: Result<Unit>) { log("Coroutine End with $result") } }).resume(Unit)
startCoroutine
startCoroutine是创建出协程后立马调用
fun <T> (suspend () -> T).startCoroutine( completion: Continuation<T> ) fun <R, T> (suspend R.() -> T).startCoroutine( receiver: R, completion: Continuation<T> )
创建和启动协程
suspend { ... }.startCoroutine(object: Continuation<Unit> { override val context = EmptyCoroutineContext override fun resumeWith(result: Result<Unit>) { log("Coroutine End with $result") } })
协程上下文
suspend { ... }.startCoroutine(object: Continuation<Unit> { override val context = EmptyCoroutineContext ... })
- 协程执行过程中需要携带数据
- 索引是CoroutineContext.Key
- 元素是CoroutineContext.Element
拦截器
- 拦截器ContinutationInterceptor是一类协程上下文元素
- 可以对协程上下文所在协程的Continuation进行拦截
interface ContinuationInterceptor: CoroutineContext.Element { fun <T> interceptContinuation( continuation: Continuation<T> ): Continuation<T> }
Continuation执行示意
suspend { ... }.startCoroutine(object: Continuation<Unit> { override val context = EmptyCoroutineContext override fun resumeWith(result: Result<Unit>) { ... } })
通过createCoroutine或startCoroutine创建出来的类为SuspendLambda,它是Continuation的一个实现类
其中,suspend {…}为协程的本体,是协程真正的实现逻辑
如果SuspendLambda里面有挂起函数的调用,每次调用还会用SafeContinuation对SuspendLambda进行包装
SafeContinuation的作用是:
- 确保resume只被调用一次
- 确保如果在当前线程调用栈上直接调用则不会挂起
SafeContinuation可以理解为一个拦截器,它拦截的就是SuspendLambda
在前面的基础上再加上拦截器
课程收获
Beny老师的讲解非常细致,对协程设计到的要素都有细致的讲解。通过介绍如何将回调改写成挂起函数,是我对挂起函数的本质有更深刻的理解。在基本要素讲解的过程中,也让我对协程的原理有了一定的认识。
由于刚刚接触协程,刚听完还是有些似懂非懂,通过手记的整理,让我对基本要素有了更深刻的认识,后续还得多回顾几遍,争取把协程摸透。
这篇关于【九月打卡】第1天 一课掌握Kotlin 突破开发语言瓶颈的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-01-06Kotlin委托属性(1)
- 2023-06-15Kotlin协程-那些理不清乱不明的关系
- 2023-06-08[Kotlin Tutorials 21] 协程的取消
- 2023-05-26Kotlin难点
- 2023-02-23【备战春招】第16天 Kotlin实用技巧
- 2023-02-23【备战春招】第15天 Kotlin扩展Extensions技术探秘
- 2023-02-22【备战春招】第14天 深入理解Kotlin注解
- 2023-02-21【备战春招】第12天 深入理解Kotlin类与接口
- 2023-02-21【备战春招】第13天 深入理解Kotlin泛型
- 2023-02-18【备战春招】第10天 Kotlin方法与Lambda表达式