Kotlin协程的介绍

一,什么是协程:

官方的介绍:

协程是一种并发设计模式,在Android平台上可以使用协程简化异步执行代码。(协程可以使我们是同步的代码形式实现异步任务的执行)

协程的特点:

  1. 轻量:一个线程上可以运行多个协程,协程支持挂起,协程的挂起不会阻塞运行协程的线程。挂起比阻塞更节省内存,也能让线程得到充分的利用。
  2. 内存泄漏更少:使用结构化并发在一个范围内(协程作用域)运行多项操作。
  3. 内置取消支持:取消通过正在运行的协程层次结构,自动传播。
  4. Jetpack集成:JetPack库提供了全面支持协程的扩展,提供了类似LifecycleScope,ViewModelScope绑定生命周期的作用域。

二,协程的使用:

1,添加相关依赖:

project的build.gradle中添加Kotlin编译插件

js 复制代码
dependencies {
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.32"
}

app的build.gradle中添加协程相关的依赖库。

js 复制代码
dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.4.32"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3"
}

2,构建启动一个协程

构建启动协程常用三种方式:

runBlocking:创建并启动一个新的线程,并且会阻塞当前的线程,直到协程内所有逻辑 和 子协程都执行完毕。项目中用不了,主要在@test测试代码中使用。

launch: 启动创建一个新的协程而不阻塞当前的线程。返回一个协程引用Job对象。

js 复制代码
public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job 

context: 协程的上下文,协程的运行环境。可以是多个上下文组合,包括调度器(Dispatchers.Default)、协程本身的job、协程的名称(CoroutineName)、异常处理器(CoroutineExceptionHandler)

start: 协程的启动模式,立即启动 或 懒启动(Lazy)

block:是一个无参、无返回值的挂起函数,我们业务逻辑实现方法。

Job:协程的任务对象,可以通过Job 获取协程的状态和对协程执行操作。isActive()判断是否活跃,start()启动协程,cancel取消协程,join()挂起协程直到此job执行完成等,

java 复制代码
fun test(){
    val job = MainScope().launch{
        Log.i("wang", "launch")
        delay(1000)//挂起函数
        Log.i("wang", "after one second")
        //两个launch构建并启动
        val job1= launch {
            delay(3000)
            Log.i("wang", "launch1")
        }
        launch {
            delay(3000)
            Log.i("wang", "launch2")
        }
        job1.join()//等待协程执行完,也是挂起函数,非阻塞的
        launch {
            delay(2000)
            Log.i("wang", "launch3")
        }
    }
    Log.i("wang", "end")
}

运行结果:

js 复制代码
2025-04-28 09:53:32.449 14296-14296 wang                    I  end
2025-04-28 09:53:32.452 14296-14296 wang                    I  launch
2025-04-28 09:53:33.454 14296-14296 wang                    I  after one second
2025-04-28 09:53:36.467 14296-14296 wang                    I  launch1
2025-04-28 09:53:36.471 14296-14296 wang                    I  launch2
2025-04-28 09:53:38.480 14296-14296 wang                    I  launch3

async:启动创建一个新的协程而不阻塞当前的线程。返回一个协程引用Deffered对象。

js 复制代码
public fun <T> CoroutineScope.async(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Deferred<T> 

block: 无参、有返回值T的挂起函数,较launch多了返回值。

Deffered: 是Job的子类,较Job多了个await()挂起函数,用于等待协程执行的结果返回值。

java 复制代码
fun testAsync(){
    MainScope().launch {
        val deferred1 = async {
            delay(1000)
            Log.i("wang", "deferred1 execute")
            100
        }
        val deferred2 = async {
            delay(2000)
            Log.i("wang", "deferred2 execute")
            200
        }
        val deferred3 = async {
            delay(3000)
            Log.i("wang", "deferred3 execute")
            300
        }
        Log.i("wang", "sum = " + (deferred1.await() + deferred2.await() + deferred3.await()))
    }
}

运行结果:

js 复制代码
2025-04-27 18:28:37.134  9747-9747  wang                    com.example.myapplication            I  deferred1 execute
2025-04-27 18:28:38.134  9747-9747  wang                    com.example.myapplication            I  deferred2 execute
2025-04-27 18:28:39.136  9747-9747  wang                    com.example.myapplication            I  deferred3 execute
2025-04-27 18:28:39.137  9747-9747  wang                    com.example.myapplication            I  sum = 600

3,协程的作用域

GlobalScope:作用域是全局,与应用程序的生命周期绑定。

coroutineScope: 创建一个独立协程作用域,所有的子协程都执行完了以后才结束自身,当前有一个子协程抛出异常后,所有未执行完成的子协程+自身都会停止执行。

superVisorScope: 同上类似,不同是子协程出现异常,不会影响父协程,也不会影响同阶的子协程。相当于在launch(SuperVisorJob())

MainScope():上下文是SupervisorJob() + Dispatchers.Main。一个在主线程执行的协程作用域。

lifecycleScope:具有生命周期感知的协程作用域,与Lifecycle生命周期绑定,生命周期结束时,此作用域将被取消。

viewModelScope: 与lifecycleScope类似,与ViewModel的生命周期绑定。

4,协程调度器

Kotlin 提供了四个调度器,您可以使用它们来指定应在何处运行协程:

调度器 介绍
Dispatchers.Default 默认调度器,非主线程。CPU密集型任务调度器。用于json解析,数据处理
Dispatchers.Main UI调度器, Andorid 上的主线程。用于UI更新
Dispatchers.Unconfined 非指定线程的协程调度器,取决于启动的线程。
Dispatchers.IO IO调度器,非主线程,执行的线程是IO线程。用于网络请求,数据库处理、文件读写

5,suspend挂起函数

suspend:是kotlin的核心关键字,使用suspend关键字修饰的函数叫挂起函数,挂起函数只能在协程中或其他挂起函数中执行。

协程在执行到有suspend标记的挂起函数时,当前函数会被挂起(暂停),直到该挂起函数内部逻辑完成,才会在挂起的地方resume恢复继续执行,而不会阻塞运行协程的线程。

java 复制代码
private fun testSuspend(){
    //启动了一个协程,去执行一个挂起函数
    Log.i("wang", "start")
    MainScope().launch {
        Log.i("wang", "start")
        val result = doWorkBackGroup()
        Log.i("wang", "result$result")
    }
}

private suspend fun doWorkBackGroup(): String{
    //模拟耗时任务
    delay(1000)
    Log.i("wang", "doWorkBackGroup end")
    return "hello world"
}

执行结果如下:

js 复制代码
2025-04-28 17:34:21.049 27706-27706 wang                  I  start
2025-04-28 17:34:22.051 27706-27706 wang                  I  doWorkBackGroup end
2025-04-28 17:34:22.052 27706-27706 wang                  I  resulthello world

源码分析:KotlinBytecode后在deCompile后的代码如下,多了一个编译器加的参数Continuation,有个接口方法resumeWith(result), 即挂起函数执行完毕后恢复的回调。

java 复制代码
private final Object doWorkBackGroup(Continuation $completion) {
kotlin 复制代码
@kotlin.SinceKotlin public interface Continuation<in T> {
    public abstract val context: kotlin.coroutines.CoroutineContext

    public abstract fun resumeWith(result: kotlin.Result<T>): kotlin.Unit
}
相关推荐
程序员江同学14 小时前
Kotlin 技术月报 | 2025 年 7 月
android·kotlin
_frank22217 小时前
kotlin使用mybatis plus lambdaQuery报错
开发语言·kotlin·mybatis
Bryce李小白17 小时前
Kotlin实现Retrofit风格的网络请求封装
网络·kotlin·retrofit
ZhuYuxi33317 小时前
【Kotlin】const 修饰的编译期常量
android·开发语言·kotlin
jzlhll12317 小时前
kotlin StateFlow的两个问题和使用场景探讨
kotlin·stateflow
Bryce李小白17 小时前
Kotlin 实现 MVVM 架构设计总结
android·开发语言·kotlin
Kiri霧17 小时前
Kotlin位运算
android·开发语言·kotlin
xjdkxnhcoskxbco17 小时前
kotlin基础【3】
android·开发语言·kotlin
小趴菜822718 小时前
自定义View和动画学习记录 抓娃娃机View
android·kotlin·动画·自定义view
金銀銅鐵1 天前
Kotlin 中的运算符重载在 class 文件中是如何实现的?(第一部分)
java·kotlin