在 Android 中使用协程(Coroutine)是简化异步操作(如网络请求、数据库操作、UI 更新)的最佳实践之一。它能以同步代码的形式编写异步逻辑,避免回调地狱,同时自动处理线程切换,非常适合 Android 开发场景。
一、准备工作:添加依赖
首先,在 app/build.gradle 中添加协程相关依赖(确保版本兼容):
gradle
dependencies {
    // 核心协程库
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
    // Android 专用协程(含主线程调度器等)
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
    // (可选)与生命周期组件集成(如 lifecycleScope)
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'
    // (可选)与 ViewModel 集成(viewModelScope)
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
}
        二、核心概念与 Android 场景结合
在 Android 中使用协程,需重点关注 作用域(Scope) 、调度器(Dispatcher) 和 暂停函数(Suspend Function),它们直接影响协程的生命周期和线程管理。
1. 协程作用域(Coroutine Scope)
作用域用于管理协程的生命周期,确保协程在不需要时被取消(如页面销毁时),避免内存泄漏。Android 中常用的作用域:
| 作用域 | 适用场景 | 生命周期 | 
|---|---|---|
lifecycleScope | 
Activity/Fragment | 随组件销毁(onDestroy)而取消 | 
viewModelScope | 
ViewModel | 随 ViewModel 销毁而取消 | 
CoroutineScope | 
自定义场景(如全局任务) | 需手动管理(通过 Job 取消) | 
示例:在 Activity 中使用 lifecycleScope lifecycleScope 是 androidx.lifecycle:lifecycle-runtime-ktx 提供的扩展,自动绑定组件生命周期:
kotlin
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 启动协程(自动在 Activity 销毁时取消)
        lifecycleScope.launch {
            // 协程逻辑(如网络请求)
            val data = fetchDataFromNetwork()
            // 自动切换到主线程更新 UI
            binding.textView.text = data
        }
    }
}
        示例:在 ViewModel 中使用 viewModelScope viewModelScope 随 ViewModel 生命周期自动取消,适合数据加载:
kotlin
class MyViewModel : ViewModel() {
    fun loadData() {
        // 启动协程(ViewModel 销毁时自动取消)
        viewModelScope.launch {
            val data = repository.getData()
            // 更新 LiveData(通知 UI)
            _uiState.value = data
        }
    }
}
        2. 调度器(Dispatcher):指定协程运行的线程
Android 中关键的调度器:
| 调度器 | 作用 | 适用场景 | 
|---|---|---|
Dispatchers.Main | 
运行在 Android 主线程(UI 线程) | 更新 UI(如设置 TextView 文本) | 
Dispatchers.IO | 
运行在 IO 线程池(专门处理 IO 操作) | 网络请求、数据库操作、文件读写 | 
Dispatchers.Default | 
运行在 CPU 密集型线程池 | 复杂计算、数据排序等 CPU 密集任务 | 
注意:
lifecycleScope和viewModelScope的默认调度器是Dispatchers.Main(主线程),但可通过参数指定其他调度器。- 耗时操作(如网络请求)必须放在 
Dispatchers.IO或Dispatchers.Default中,避免阻塞主线程。 
3. 暂停函数(Suspend Function)
用 suspend 关键字标记的函数,只能在协程或其他暂停函数中调用。它可以「暂停」执行(释放线程),待任务完成后再「恢复」,但不会阻塞线程。
示例:定义一个网络请求的暂停函数 结合 Retrofit 使用时,可直接将接口方法定义为 suspend 函数(Retrofit 2.6+ 支持):
kotlin
// 网络接口(Retrofit)
interface ApiService {
    @GET("data")
    suspend fun fetchData(): Response<Data> // 暂停函数,自动在 IO 线程执行
}
// 仓库层调用
class DataRepository(private val api: ApiService) {
    // 暂停函数:封装网络请求
    suspend fun getData(): Data {
        val response = api.fetchData()
        if (response.isSuccessful) {
            return response.body() ?: throw Exception("空数据")
        } else {
            throw Exception("请求失败")
        }
    }
}
        三、完整示例:从网络请求到更新 UI
下面是一个完整流程:在 Activity 中启动协程 → 切换到 IO 线程执行网络请求 → 切换回主线程更新 UI。
kotlin
class MainActivity : AppCompatActivity() {
    private val apiService by lazy { RetrofitClient.create(ApiService::class.java) }
    private val repository by lazy { DataRepository(apiService) }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        // 点击按钮触发数据加载
        binding.loadButton.setOnClickListener {
            loadData()
        }
    }
    private fun loadData() {
        // 用 lifecycleScope 启动协程(默认在主线程)
        lifecycleScope.launch {
            // 显示加载中状态
            binding.progressBar.visibility = View.VISIBLE
            try {
                // 切换到 IO 线程执行网络请求(withContext 会暂停当前协程,执行完后恢复)
                val data = withContext(Dispatchers.IO) {
                    repository.getData() // 调用暂停函数
                }
                // 自动切回主线程,更新 UI
                binding.textView.text = data.content
                binding.progressBar.visibility = View.GONE
            } catch (e: Exception) {
                // 处理异常(如网络错误)
                binding.textView.text = "加载失败:${e.message}"
                binding.progressBar.visibility = View.GONE
            }
        }
    }
}
        关键说明:
withContext(Dispatchers.IO):将代码块切换到 IO 线程执行,执行完毕后自动切回原调度器(这里是主线程)。try-catch:捕获网络请求可能抛出的异常(如超时、数据为空),避免应用崩溃。
四、取消协程(避免内存泄漏)
协程作用域(如 lifecycleScope、viewModelScope)会自动取消协程,但如果是自定义作用域,需手动管理:
kotlin
// 自定义作用域(需手动取消)
val customScope = CoroutineScope(Dispatchers.Main + Job())
fun startTask() {
    customScope.launch {
        repeat(10) {
            delay(1000) // 模拟耗时操作
            Log.d("Coroutine", "执行中:$it")
        }
    }
}
// 在不需要时取消(如页面销毁)
fun cancelTask() {
    customScope.cancel() // 取消作用域内所有协程
}
        五、常见场景与最佳实践
- 
并行请求 :用
async同时发起多个请求,再用awaitAll等待全部完成:kotlin
lifecycleScope.launch { val deferred1 = async(Dispatchers.IO) { repository.getData1() } val deferred2 = async(Dispatchers.IO) { repository.getData2() } val result1 = deferred1.await() val result2 = deferred2.await() // 处理两个结果 } - 
延迟任务 :用
delay()替代Handler.postDelayed():kotlin
lifecycleScope.launch { delay(2000) // 延迟 2 秒(非阻塞) binding.textView.text = "延迟后更新" } - 
与 Room 配合 :Room 支持
suspend函数,直接在协程中调用数据库操作:kotlin
@Dao interface UserDao { @Query("SELECT * FROM user") suspend fun getUsers(): List<User> // 暂停函数,自动在 IO 线程执行 } 
总结
在 Android 中使用协程的核心是:
- 用 
lifecycleScope或viewModelScope管理生命周期,避免泄漏; - 用 
Dispatchers.IO处理耗时操作,Dispatchers.Main更新 UI; - 用 
suspend函数封装异步逻辑,用withContext切换线程。 
协程让异步代码更简洁、可读性更强,是 Android 开发的首选异步方案。