跳转到内容

Kotlin协程

来自代码酷
  1. Kotlin协程

Kotlin协程是Kotlin语言提供的一种轻量级并发编程解决方案,它简化了异步编程和并发操作的管理。协程允许开发者以顺序的方式编写异步代码,同时保持高效的资源利用。

    1. 概述

Kotlin协程基于以下核心概念:

  • **轻量级线程**:比传统线程更高效,可创建数千个协程而不会导致性能问题
  • **挂起函数**:使用`suspend`关键字标记,可以在不阻塞线程的情况下暂停执行
  • **结构化并发**:提供明确的生命周期管理和错误传播机制
  • **协程上下文**:定义协程执行的环境,包括调度器、异常处理器等
    1. 基本用法
      1. 启动协程

Kotlin提供了几种启动协程的方式:

// 使用GlobalScope启动协程(不推荐在生产代码中使用)
GlobalScope.launch {
    // 协程体
    fetchData()
}

// 推荐的方式:使用CoroutineScope
val scope = CoroutineScope(Dispatchers.Main)
scope.launch {
    // 在主线程执行的协程
    val result = fetchData()
    updateUI(result)
}
      1. 挂起函数

挂起函数是协程的核心构建块:

suspend fun fetchData(): String {
    return withContext(Dispatchers.IO) {
        // 模拟网络请求
        delay(1000) // 非阻塞延迟
        "数据加载完成"
    }
}
    1. 协程调度器

Kotlin提供了几种预定义的调度器:

  • **Dispatchers.Main**:Android主线程
  • **Dispatchers.IO**:适合I/O密集型操作
  • **Dispatchers.Default**:适合CPU密集型操作
  • **Dispatchers.Unconfined**:不限定特定线程
    1. 结构化并发

Kotlin协程通过结构化并发管理协程生命周期:

class MyActivity : AppCompatActivity(), CoroutineScope by MainScope() {
    
    override fun onDestroy() {
        super.onDestroy()
        cancel() // 取消所有子协程
    }
    
    fun loadData() {
        launch {
            try {
                val data = fetchData()
                showData(data)
            } catch (e: Exception) {
                showError(e)
            }
        }
    }
}
    1. 协程与Android应用

在Android开发中,协程常用于以下场景:

1. **网络请求**:替代回调或RxJava 2. **数据库操作**:Room数据库支持协程 3. **UI更新**:在主线程安全地更新UI 4. **并行任务**:使用`async/await`模式

示例:结合ViewModel使用协程

class MyViewModel : ViewModel() {
    private val repository = DataRepository()
    
    val data = liveData {
        emit(Resource.loading())
        try {
            emit(Resource.success(repository.fetchData()))
        } catch (e: Exception) {
            emit(Resource.error(e))
        }
    }
}
    1. 高级特性
      1. 协程上下文

可以自定义协程上下文:

val customDispatcher = Executors.newFixedThreadPool(4).asCoroutineDispatcher()
val exceptionHandler = CoroutineExceptionHandler { _, exception ->
    println("协程异常: $exception")
}

val customContext = customDispatcher + exceptionHandler
      1. 通道(Channel)

协程间的通信机制:

val channel = Channel<Int>()

launch {
    for (x in 1..5) channel.send(x)
    channel.close()
}

launch {
    for (y in channel) println(y)
}
      1. 流(Flow)

异步数据流处理:

fun fetchItems(): Flow<Item> = flow {
    for (i in 1..10) {
        delay(100)
        emit(Item(i))
    }
}

launch {
    fetchItems()
        .filter { it.id % 2 == 0 }
        .collect { item -> println(item) }
}
    1. 性能优势

Kotlin协程相比传统线程的优势:

  • **内存占用低**:协程栈可复用,创建成本低
  • **调度高效**:协程切换不涉及操作系统线程切换
  • **资源可控**:通过调度器限制并发数量
  • **错误处理**:结构化并发简化错误传播
    1. 常见问题
      1. 协程与线程的区别

| 特性 | 协程 | 线程 | |------|------|------| | 创建成本 | 低 | 高 | | 切换开销 | 小 | 大 | | 并发数量 | 数千 | 数百 | | 调度方式 | 协作式 | 抢占式 | | 内存占用 | 几十KB | 几MB |

      1. 协程泄漏

协程泄漏常见原因:

  • 忘记取消不再需要的协程
  • 在已销毁的Activity/Fragment中继续运行协程
  • 持有外部对象的强引用

解决方案:

  • 使用结构化并发
  • 实现CoroutineScope接口
  • 使用viewModelScope或lifecycleScope
    1. 最佳实践

1. **避免GlobalScope**:使用自定义作用域 2. **正确处理异常**:使用CoroutineExceptionHandler 3. **合理选择调度器**:根据任务类型选择 4. **测试协程代码**:使用TestCoroutineDispatcher 5. **结合LiveData使用**:使用liveData构建器

    1. 相关库
  • **kotlinx.coroutines**:官方协程库
  • **Room**:支持协程的数据库库
  • **Retrofit**:支持协程的网络库
  • **WorkManager**:支持协程的后台任务调度
    1. 参见