跳至正文

🚀 为什么选择协程?

📖 什么是协程?

**协程(Coroutines)**是 Kotlin 的核心功能,它让异步编程变得简单而直观。从复杂的回调地狱中解脱出来,像编写同步代码一样编写异步代码!

💡 传统异步的问题

回调地狱

// ❌ 回调方式(难以阅读和维护)
fun fetchUser(userId: String, callback: (User?) -> Unit) {
fetchFromNetwork(userId) { result ->
if (result != null) {
fetchProfile(result.id) { profile ->
if (profile != null) {
fetchPosts(profile.id) { posts ->
callback(User(result, profile, posts))
}
} else {
callback(null)
}
}
} else {
callback(null)
}
}
}

线程的开销

// ❌ 线程很昂贵
fun downloadFiles() {
repeat(1000) {
Thread {
// 每个线程占用大量内存
downloadFile("file_$it.txt")
}.start()
}
// 可能内存不足!
}

✨ 协程的优势

1. 简洁的代码

// ✅ 协程(易读且直观)
suspend fun fetchUser(userId: String): User? {
val result = fetchFromNetwork(userId) ?: return null
val profile = fetchProfile(result.id) ?: return null
val posts = fetchPosts(profile.id)
return User(result, profile, posts)
}

2. 轻量级并发

// ✅ 数千个协程也没问题
suspend fun downloadFiles() {
coroutineScope {
repeat(10000) {
launch {
// 轻量级协程!
downloadFile("file_$it.txt")
}
}
}
}

3. 结构化并发

// ✅ 自动管理生命周期
suspend fun processData() {
coroutineScope {
val job1 = launch { task1() }
val job2 = launch { task2() }

// 所有任务结束后自动完成
}
}

🎯 实际使用示例

网络请求

// 无需回调,简洁明了!
suspend fun loadUserData(userId: String): UserData {
val user = apiService.getUser(userId)
val posts = apiService.getPosts(userId)
val friends = apiService.getFriends(userId)

return UserData(user, posts, friends)
}

UI 更新

// 不阻塞主线程
suspend fun updateUI() {
val data = withContext(Dispatchers.IO) {
// 在后台加载数据
loadDataFromDatabase()
}

// 在主线程更新 UI
updateViews(data)
}

并行处理

// 同时执行多个任务!
suspend fun fetchAllData(): CombinedData = coroutineScope {
val users = async { fetchUsers() }
val products = async { fetchProducts() }
val orders = async { fetchOrders() }

CombinedData(
users.await(),
products.await(),
orders.await()
)
}

🔥 协程 vs 线程

特性协程线程
重量非常轻量重量级
创建成本几乎为零昂贵
数量可达数万个数千个为限
切换成本
取消简单困难

性能比较

// 协程:运行 100,000 个
suspend fun testCoroutines() {
val time = measureTimeMillis {
coroutineScope {
repeat(100_000) {
launch {
delay(1000)
}
}
}
}
println("协程: ${time}ms") // ~1000ms
}

// 线程:即使只有 10,000 个...
fun testThreads() {
val time = measureTimeMillis {
repeat(10_000) {
Thread {
Thread.sleep(1000)
}.start()
}
}
println("线程: ${time}ms") // 可能内存不足!
}

🎨 协程的核心概念

Suspend(挂起)

// suspend 函数只能在协程内调用
suspend fun doWork() {
delay(1000) // 不阻塞线程而是等待
println("任务完成")
}

结构化并发

// 通过父子关系管理生命周期
fun main() = runBlocking {
launch { // 父级
launch { // 子级 1
delay(1000)
println("子级 1 完成")
}
launch { // 子级 2
delay(2000)
println("子级 2 完成")
}
println("父级等待子级结束")
}
}

🤔 常见问题

Q1. 协程是新的线程吗?

A: 不是!协程是在线程上运行的轻量级工作单元。

// 在一个线程上可以运行多个协程
fun main() = runBlocking {
repeat(3) { i ->
launch {
println("协程 $i: ${Thread.currentThread().name}")
}
}
}
// 它们都可以在同一个线程上运行!

Q2. 需要把所有函数都改成 suspend 吗?

A: 不需要!只有需要异步操作的函数才需要改成 suspend。

// ❌ 不需要
suspend fun add(a: Int, b: Int) = a + b

// ✅ 需要
suspend fun fetchData() = withContext(Dispatchers.IO) {
loadFromNetwork()
}

Q3. 什么时候应该使用协程?

A: 在这些情况下使用!

// ✅ 网络请求
suspend fun loadData() = api.fetchData()

// ✅ 数据库操作
suspend fun saveUser(user: User) = db.insert(user)

// ✅ 文件 I/O
suspend fun readFile(path: String) = withContext(Dispatchers.IO) {
File(path).readText()
}

// ✅ 长时间计算任务
suspend fun heavyComputation() = withContext(Dispatchers.Default) {
// 复杂计算
}

🎬 总结

用协程让异步编程变简单!

核心要点:
✅ 摆脱回调地狱
✅ 轻量级并发
✅ 直观的代码
✅ 结构化的生命周期
✅ 比线程更高效

下一步: 在协程基础中实际使用协程!