1. 不必要的线程切换
问题:在 Retrofit 的 suspend 函数外额外包裹 withContext(Dispatchers.IO)
// ❌ 冗余的线程切换
suspend fun fetchData(): Response<Data> {
return withContext(Dispatchers.IO) {
retrofitService.getData()
}
}
// ✅ 简洁正确的写法
suspend fun fetchData(): Response<Data> {
return retrofitService.getData()
}
最佳实践:Retrofit 的 suspend 函数已自动在 IO 线程执行,无需额外切换。
2. 错误的并行处理方式
问题:使用串行的 launch 而非并行的 async 执行独立任务
// ❌ 串行执行网络请求
lifecycleScope.launch {
val data1 = fetchDataFromNetwork1() // 等待完成
val data2 = fetchDataFromNetwork2() // 才开始
}
// ✅ 并行执行网络请求
lifecycleScope.launch {
val deferredData1 = async { fetchDataFromNetwork1() }
val deferredData2 = async { fetchDataFromNetwork2() }
val (data1, data2) = awaitAll(deferredData1, deferredData2)
}
最佳实践:独立任务应使用 async 并行执行,最后统一等待结果。
3. 过早等待异步结果
问题:立即 await() 导致失去并行优势
// ❌ 伪并行
suspend fun fetchData() {
val data1 = async { fetchDataFromNetwork1() }.await()
val data2 = async { fetchDataFromNetwork2() }.await()
}
// ✅ 真正的并行
suspend fun fetchData() {
val deferredData1 = async { fetchDataFromNetwork1() }
val deferredData2 = async { fetchDataFromNetwork2() }
val (data1, data2) = awaitAll(deferredData1, deferredData2)
}
最佳实践:先启动所有异步任务,最后统一等待,最大化并行效率。
4. 未正确使用IO调度器
问题:在主线程执行文件操作等耗时任务
// ❌ 危险的主线程IO操作
suspend fun readFile(): String {
return File("path/to/file").readText()
}
// ✅ 正确的IO线程处理
suspend fun readFile(): String {
return withContext(Dispatchers.IO) {
File("path/to/file").readText()
}
}
最佳实践:文件操作等阻塞任务必须明确指定 Dispatchers.IO。
5. 混用阻塞与非阻塞操作
问题:在协程中使用 Thread.sleep() 等阻塞调用
// ❌ 危险的阻塞操作
fun fetchData() {
lifecycleScope.launch {
val data = fetchDataFromNetwork()
Thread.sleep(1000) // 阻塞整个线程
}
}
// ✅ 正确的挂起方式
fun fetchData() {
lifecycleScope.launch {
val data = fetchDataFromNetwork()
delay(1000) // 非阻塞挂起
}
}
最佳实践:始终使用 delay() 等挂起函数替代阻塞操作。
总结对比表
| 错误类型 | 错误示例 | 正确写法 | 关键改进 |
|---|---|---|---|
| 冗余线程切换 | withContext(IO){retrofitCall} | 直接调用retrofit | 避免不必要的上下文切换 |
| 串行并行混淆 | 顺序launch调用 | 使用async并行 | 最大化任务并行度 |
| 过早等待 | 立即await() | 最后统一awaitAll | 保持并行优势 |
| 线程选择不当 | 主线程IO操作 | withContext(IO) | 正确使用调度器 |
| 阻塞操作 | Thread.sleep() | delay() | 保持协程非阻塞特性 |
掌握这些最佳实践,您将能够:
- 避免常见的协程使用误区
- 编写更高效的异步代码
- 充分利用协程的并发优势
- 保证应用响应性能
正确使用协程可以显著提升应用性能,同时保持代码的简洁性和可维护性。