持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情
定义
协程是轻量级线程。
协程不是线程的替代品。它们只为我们提供了一个框架来有效地管理我们已经熟悉的线程。线程数量有限,但我们可以拥有任意数量的协程。线程由操作系统管理,而协程由 用户管理。多个协程可以在单个线程上运行,从而以更有效的方式利用一个线程。当一个线程处于空闲状态并且可以执行其他函数的几行而不是只是一个函数,换句话说,协程比 JVM 线程占用更少的资源。
引入
在 Android 上使用时添加kotlinx-coroutines-android 模块作为依赖项:kotlinx.coroutines
// gradle.kts
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0")
基础使用
挂起函数
一个可以暂停和恢复的函数,挂起函数的语法与常规函数的语法类似,不同之处在于添加了suspend关键字。它可以接受一个参数并有一个返回类型。但是,挂起函数只能由另一个挂起函数或在协程范围内调用。
suspend fun functionA(){
...
}
协程构建器
- Launch:是一种不返回任何值的协程,特点就是随时发起随时弃用。
GlobalScope.launch(Dispatchers.IO) {
...
}
- Async:
async{}返回一个 的实例Deferred<T>,它有一个await()返回协程结果的函数。
GlobalScope.launch(Dispatchers.Main) {
val fA = async(Dispatchers.IO) { functionA() }
val fB = async(Dispatchers.IO) { functionB() }
// 返回UI线程
functionC(fA.await(), fB.await())
}
- RunBlocking: 是一个协程函数。通过不提供任何上下文,它将在主线程上运行。运行一个新的协程并阻塞当前线程可中断,直到它完成。不应在协程中使用此函数。它旨在将常规阻塞代码连接到以挂起样式编写的库,以用于主要功能和测试。
fun functionA() = runBlocking { // this: CoroutineScope
launch { // 在 runBlocking 作用域中启动一个新协程
delay(1000L)
println("协程中的输出后显示")
}
println("协程外的输出先显示")
}
协程调度器
Dispatcher 基本上确定协程在哪个线程或线程池上运行。因此,如果您不想定义调度程序,则不一定需要
- Dispatchers.Main:当需要将数据展示到UI上。
runBlocking {
launch(Dispatchers.Main) {
Log.d("Dispatcher", "Dispatchers.Main线程: ${Thread.currentThread().name}")
}
}
- Dispatchers.Default:用于执行 CPU 密集型工作,例如搜索、排序或过滤数据。
runBlocking {
launch(Dispatchers.Default) {
Log.d("Dispatcher", "Dispatchers.Default线程: ${Thread.currentThread().name}")
}
}
- Dispatchers.IO:用于网络通信或读/写文件,进行API调用或存储到数据库。
runBlocking {
launch(Dispatchers.IO) {
Log.d("Dispatcher", "Dispatchers.IO线程: ${Thread.currentThread().name}")
}
}
- Dispatchers.Unconfined:在调用它的继承调度程序中启动协程
runBlocking {
launch(Dispatchers.Unconfined) {
Log.d("Dispatcher", "1---Dispatchers.Unconfined线程: ${Thread.currentThread().name}")
delay(1000L)
Log.d("Dispatcher", "2---Dispatchers.Unconfined线程: ${Thread.currentThread().name}")
}
}