Kotlin 协程 (一)

1. Kotlin 协程的核心概念

1.1 协程(Coroutine)
  • 定义:协程是一种轻量级的执行上下文,可以在任何时候挂起和恢复,而不需要阻塞线程。
  • 特点
    • 比传统线程更轻量,开销更小。
    • 支持挂起和恢复,避免了阻塞线程和资源浪费。
    • 提供更简洁的并发编程方式。
1.2 挂起函数(Suspend Function)
  • 定义 :使用 suspend 关键字修饰的函数,可以在协程中挂起执行,挂起期间不会阻塞线程。
  • 作用:允许协程在等待任务完成时释放线程资源,待任务完成后恢复执行。
1.3 协程作用域(Coroutine Scope)
  • 定义:协程作用域定义了协程的生命周期,确保协程在作用域结束时被取消。
  • 常见作用域
    • GlobalScope:全局作用域,生命周期与整个应用程序一致(不推荐用于实际开发)。
    • CoroutineScope:自定义作用域,可通过 CoroutineScope(Dispatchers) 创建。
    • runBlocking:用于测试场景,会阻塞当前线程直到协程完成。
1.4 协程构建器(Coroutine Builders)
  • launch:启动一个协程,不返回结果。
  • async :启动一个协程,并返回一个 Deferred 对象,可用于获取结果。
  • runBlocking:阻塞当前线程,直到协程完成(仅用于测试)。

2. Kotlin 协程的使用方法

以下是协程使用的基本步骤:

2.1 添加依赖项

在项目的 build.gradle 文件中添加 Kotlin 协程库依赖:

复制代码
dependencies {
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0'
}
2.2 创建协程作用域

协程必须在协程作用域中运行。例如:

Kotlin 复制代码
import kotlinx.coroutines.*

fun main() = runBlocking { // 用于测试,实际开发中避免使用
    val scope = CoroutineScope(Dispatchers.Default)
    scope.launch {
        // 在这里执行异步任务
    }
}
2.3 启动协程

使用 launchasync 启动协程:

  • launch:用于不需要返回结果的异步任务。
  • async:用于需要返回结果的异步任务。
Kotlin 复制代码
scope.launch {
    delay(1000L) // 模拟耗时操作
    println("异步任务完成")
}

val deferred = scope.async {
    delay(1000L)
    "异步任务结果"
}
println("异步任务返回值: ${deferred.await()}")
2.4 使用挂起函数

挂起函数允许协程在等待任务时挂起,例如 delay

Kotlin 复制代码
suspend fun fetchData(): String {
    delay(1000L) // 模拟网络请求
    return "Data fetched"
}

3. Kotlin 协程的具体示例

以下通过几个常见场景展示协程的实际用法。

3.1 简单的异步任务

使用 launch 启动一个异步任务:

Kotlin 复制代码
import kotlinx.coroutines.*

fun main() = runBlocking {
    launch {
        delay(1000L)
        println("World!")
    }
    println("Hello,")
}
  

输出:
Hello,
World!
3.2 并行任务与结果获取

使用 asyncawait 实现并行任务:

Kotlin 复制代码
import kotlinx.coroutines.*

fun main() = runBlocking {
    val deferred1 = async {
        fetchDataFromNetwork1()
    }
    val deferred2 = async {
        fetchDataFromNetwork2()
    }
    println("Data1: ${deferred1.await()}")
    println("Data2: ${deferred2.await()}")
}

suspend fun fetchDataFromNetwork1(): String {
    delay(1000L)
    return "NetworkData1"
}

suspend fun fetchDataFromNetwork2(): String {
    delay(1000L)
    return "NetworkData2"
}
3.3 取消协程

使用 cancel 方法取消协程:

Kotlin 复制代码
import kotlinx.coroutines.*

fun main() = runBlocking {
    val job = launch {
        delay(5000L)
        println("Task completed")
    }
    delay(1000L)
    job.cancel()
    println("Coroutine cancelled")
}

4.实际应用示例

网络请求与数据库操作

Kotlin 复制代码
// 假设有以下挂起函数
suspend fun fetchUserData(): UserData = withContext(Dispatchers.IO) {
    // 模拟网络请求
    delay(1000)
    UserData("John", 30)
}

suspend fun saveToDatabase(user: UserData) = withContext(Dispatchers.IO) {
    // 模拟数据库操作
    delay(500)
    println("User saved: $user")
}

data class UserData(val name: String, val age: Int)

fun main() = runBlocking {
    // 顺序执行
    val user = fetchUserData()
    saveToDatabase(user)
    
    // 并发执行多个网络请求
    val users = listOf("user1", "user2", "user3")
    val deferredList = users.map { userId ->
        async { fetchUserDataForId(userId) }
    }
    val results = deferredList.awaitAll()
    println("All users fetched: $results")
}

suspend fun fetchUserDataForId(userId: String): UserData {
    delay(1000)
    return UserData("$userId-Name", 20 + userId.last().digitToInt())
}

5. 总结

  • 核心概念:协程、挂起函数、协程作用域和协程构建器是协程编程的基础。
  • 使用方法:通过添加依赖、创建作用域、启动协程和使用挂起函数,可以轻松实现异步编程。
  • 适用场景:协程适用于网络请求、文件 IO、CPU 密集型任务等需要并发处理的场景。
相关推荐
阿巴斯甜15 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker16 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952717 小时前
Andorid Google 登录接入文档
android
黄林晴18 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_2 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android