https://www.bbsmax.com/A/kmzLNEBA5G/
https://blog.51cto.com/u_15548643/5153793(结合实例代码更易懂,有一处注释有问题。)
https://zhuanlan.zhihu.com/p/427092689(知乎)
https://www.jianshu.com/p/e4e7ae9473de(原理性讲解)
https://developer.android.google.cn/kotlin/coroutines?hl=zh-cn (官网教程)
目录
一、协程的意义
- 用同步的方式写出异步的代码,维持代码结构的清晰,避免回调地狱。
二、重要概念
- suspend 函数 (挂起函数)
suspend 函数只能在协程里或者另一个 suspend 函数里被调用,还是为了要让协程能够在 suspend 函数切换线程之后再切回来。
依赖包
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:x.x.x'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:x.x.x"
三、知识点概览
1. 协程构建器 (Coroutine Builders)
launch:创建一个新的协程,并返回一个Job,代表协程本身。它不返回任何结果,适用于“发后即忘”的场景。async:创建一个新的协程,返回一个Deferred<T>对象(Job的子接口)。通过在其上调用.await(),可以挂起并获取最终返回的结果。常用于并发执行任务。runBlocking:创建一个新的协程并阻塞当前线程,直到其内部所有逻辑执行完毕。它主要用于桥接普通阻塞代码和挂起风格代码(如在main函数或测试中),日常Android开发中应避免使用。
2. 挂起函数 (Suspend Functions)
- 使用
suspend关键字修饰的函数。 - 核心特性:可以在函数内部挂起当前协程的执行,而不会阻塞其所在的线程。当挂起操作(如
delay、网络请求)完成后,协程会在后续某个时间点恢复执行。 - 原理:编译时会被添加一个
Continuation参数,其函数体被编译成一个状态机,每个挂起点对应一个状态,从而用同步的方式写出异步的代码。
3. 协程上下文 (CoroutineContext)
它是协程运行环境的持久化集合,主要包含以下几个关键元素:
Job:控制协程的生命周期。可以用于判断协程是否活跃、取消协程、等待子协程完成等。每个协程都有自己的Job。CoroutineDispatcher(调度器):决定协程在哪个线程或线程池上执行。主要类型有:Dispatchers.Main:主线程,用于UI操作。Dispatchers.IO:适合执行磁盘或网络I/O操作(如文件读写、网络请求)。Dispatchers.Default:适合执行CPU密集型任务(如列表排序、JSON解析)。Dispatchers.Unconfined:不限定线程,在第一个挂起点之前运行在当前线程,之后由调用resume的线程决定(极少使用)。
CoroutineName:为协程命名,方便调试。CoroutineExceptionHandler:用于处理协程中未捕获的异常。
4. 协程作用域 (CoroutineScope)
- 定义了新启动的协程的生命周期边界。它持有自己的
CoroutineContext。 - 重要性:通过作用域可以跟踪和管理其内部所有协程。当作用域被取消时,其内部所有正在运行的协程都会被自动取消,有效防止协程泄漏。
- 常用作用域:
GlobalScope:全局作用域,生命周期与整个应用一致,一般不推荐使用。lifecycleScope(在androidx.lifecycle:lifecycle-runtime-ktx中):每个LifecycleOwner(如Activity/Fragment)都有。当Lifecycle销毁时,该作用域内的协程自动取消。viewModelScope(在androidx.lifecycle:lifecycle-viewmodel-ktx中):每个ViewModel都有。当ViewModel被清除时,其内部的协程自动取消。
5. 启动模式 (CoroutineStart)
DEFAULT:立即调度执行协程,随时可以取消。LAZY:懒加载模式,只有在需要时(如调用Job.start()、Job.join()或Deferred.await())才会开始执行。ATOMIC:类似于DEFAULT,但在开始运行前不能被取消。UNDISPATCHED:协程创建后,立即在当前线程执行,直到遇到第一个挂起点。
6. 结构化并发 (Structured Concurrency)
这是Kotlin协程的核心设计理念,其原则是:
- 父子层级:协程必须在某个
CoroutineScope中启动,形成一个父子关系。 - 生命周期继承:父协程被取消,所有子协程自动取消。父协程会等待所有子协程完成后再完成。
- 异常传播:子协程的未捕获异常会默认向上传播给父协程,导致父协程也失败。
💡 协程解决的问题
正如文章开头所述,协程优雅地解决了两个核心问题:
- 处理耗时任务:通过非阻塞挂起,将耗时操作从主线程移开,避免ANR。
- 保证主线程安全:通过调度器(
Dispatchers)方便地在不同线程间切换,并利用挂起函数保证任何suspend函数都可以安全地从主线程调用。
0 条评论