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
}
相关推荐
云深不知云4 小时前
Kotlin协程(一)协程简析
kotlin
缘来的精彩4 小时前
adb常用的20个命令
android·adb·kotlin
tangweiguo030519875 小时前
Android kotlin通知功能完整实现指南:从基础到高级功能
android·kotlin
Kapaseker5 小时前
Kotlin协程异常一文通
kotlin
louisgeek6 小时前
Kotlin 协程 coroutineScope 和 supervisorScope 的区别
kotlin
alexhilton1 天前
理解Jetpack Compose中副作用函数的内部原理
android·kotlin·android jetpack
人生游戏牛马NPC1号1 天前
学习Android(四)
android·kotlin
百锦再1 天前
Kotlin学习基础知识大全(上)
android·xml·学习·微信·kotlin·studio·mobile