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中启动,形成一个父子关系。
  • 生命周期继承:父协程被取消,所有子协程自动取消。父协程会等待所有子协程完成后再完成。
  • 异常传播:子协程的未捕获异常会默认向上传播给父协程,导致父协程也失败。

💡 协程解决的问题

正如文章开头所述,协程优雅地解决了两个核心问题:

  1. 处理耗时任务:通过非阻塞挂起,将耗时操作从主线程移开,避免ANR。
  2. 保证主线程安全:通过调度器(Dispatchers)方便地在不同线程间切换,并利用挂起函数保证任何suspend函数都可以安全地从主线程调用。
分类: 协程

0 条评论

发表回复

您的电子邮箱地址不会被公开。