Kotlin语言进阶:协程、Flow、Channel详解(一)
一、协程基础概念
1.1 什么是协程
协程(Coroutines)是Kotlin提供的一种轻量级线程的实现方案,它可以在单线程中模拟多线程编程的效果。相比传统的线程,协程具有以下优势:
- 轻量级:启动成本更低
- 内存占用少:可以同时运行大量协程
- 内置取消支持:可以自动取消整个协程层次结构
- 结构化并发:父协程可以控制子协程的生命周期
1.2 基本使用
// 启动一个协程
GlobalScope.launch {delay(1000L) // 非阻塞的等待1秒钟println("World!") // 在延迟后打印
}
print("Hello, ") // 主线程继续执行
Thread.sleep(2000L) // 阻塞主线程2秒钟来保证JVM存活
二、协程作用域
2.1 CoroutineScope
CoroutineScope定义了协程的作用范围,主要有以下几种:
// 1. GlobalScope:全局作用域,生命周期与应用程序相同
GlobalScope.launch {// 协程代码
}// 2. coroutineScope:创建一个新的作用域
suspend fun doSomething() = coroutineScope {launch {// 子协程1}launch {// 子协程2}
}// 3. Android中的viewModelScope
class MyViewModel : ViewModel() {init {viewModelScope.launch {// 协程会在ViewModel清除时自动取消}}
}
2.2 作用域构建器
// runBlocking:阻塞当前线程直到内部协程完成
fun main() = runBlocking {launch {delay(1000L)println("World!")}println("Hello")
}// supervisorScope:子协程失败不会影响其他子协程
suspend fun supervisedFunc() = supervisorScope {val first = async { doFirstThing() }val second = async { doSecondThing() }first.await() + second.await()
}
三、协程调度器
3.1 Dispatchers类型
CoroutineScope(Dispatchers.Main).launch {// UI线程
}CoroutineScope(Dispatchers.IO).launch {// IO操作线程池
}CoroutineScope(Dispatchers.Default).launch {// CPU密集型操作线程池
}CoroutineScope(Dispatchers.Unconfined).launch {// 不限制线程
}
3.2 调度器切换
CoroutineScope(Dispatchers.Main).launch {// 主线程val result = withContext(Dispatchers.IO) {// IO线程执行api.getData()}// 回到主线程updateUI(result)
}
四、实战案例
4.1 网络请求处理
class UserRepository {suspend fun getUserData(): User = withContext(Dispatchers.IO) {try {val response = api.getUser() // 网络请求response.toUser() // 数据转换} catch (e: Exception) {throw UserException("获取用户数据失败")}}
}class UserViewModel : ViewModel() {private val _user = MutableLiveData<User>()val user: LiveData<User> = _userfun loadUser() {viewModelScope.launch {try {val result = userRepository.getUserData()_user.value = result} catch (e: Exception) {// 错误处理}}}
}
4.2 并行请求处理
suspend fun loadData() = coroutineScope {val users = async { repository.getUsers() }val products = async { repository.getProducts() }val combinedData = CombinedData(users = users.await(),products = products.await())
}
五、其他
5.1 协程的启动模式
// 立即启动
launch(start = CoroutineStart.DEFAULT) { }// 懒加载启动
val job = launch(start = CoroutineStart.LAZY) { }
job.start() // 手动启动// 原子操作启动
launch(start = CoroutineStart.ATOMIC) { }// 撤销启动
launch(start = CoroutineStart.UNDISPATCHED) { }
5.2 异常处理
viewModelScope.launch {try {val result = withContext(Dispatchers.IO) {// 可能抛出异常的操作api.riskyOperation()}handleSuccess(result)} catch (e: Exception) {handleError(e)} finally {// 清理工作}
}
六、面试题解析
6.1 基础概念
Q:协程与线程的区别是什么?
A:
- 协程是轻量级的,启动成本更低(几kb内存 vs 几mb内存)
- 协程支持结构化并发,更容易管理
- 协程提供了内置的取消支持
- 协程可以在单线程上模拟多线程操作
Q:什么是挂起函数?
A:
- 挂起函数是可以暂停执行并稍后恢复的函数
- 使用suspend关键字标记
- 只能在协程或其他挂起函数中调用
- 不会阻塞线程
6.2 实践应用
Q:如何在Android中正确使用协程?
A:
- 使用适当的作用域(lifecycleScope/viewModelScope)
- 正确处理异常
- 合理选择调度器
- 注意内存泄漏
Q:协程的取消机制是如何工作的?
A:
- 通过Job对象控制协程生命周期
- 取消是协作的,需要协程代码检查取消状态
- withContext和yield函数会自动检查取消状态
- 可以使用try-finally确保资源释放
七、开源项目实战
7.1 Retrofit协程支持
interface ApiService {@GET("users")suspend fun getUsers(): List<User>
}class Repository {private val api = retrofit.create(ApiService::class.java)suspend fun getUsers(): List<User> = withContext(Dispatchers.IO) {api.getUsers()}
}
7.2 Room数据库协程操作
@Dao
interface UserDao {@Query("SELECT * FROM users")suspend fun getAll(): List<User>@Insertsuspend fun insert(user: User)
}
八、调试技巧
8.1 协程调试
// 添加调试信息
val job = launch(CoroutineName("MyCoroutine")) {log.d("协程开始执行")// ...
}// 使用Debug模式
System.setProperty("kotlinx.coroutines.debug", "on")
8.2 异常追踪
CoroutineExceptionHandler { context, exception ->println("Caught $exception")exception.printStackTrace()
}
九、总结
本文介绍了Kotlin协程的基础概念和实践应用:
- 协程的基本概念和优势
- 协程作用域和构建器的使用
- 不同类型的调度器及其应用场景
- 实战案例和性能优化建议
- 常见面试题解析
在实际开发中,建议:
- 合理使用协程作用域
- 正确处理异常情况
- 选择合适的调度器
- 注意性能优化
下一篇文章将深入介绍Flow和Channel的使用。