为什么现在都在用ref="/tag/2032/" style="color:#B2A89E;font-weight:bold;">Kotlin协程?
做过Android开发的都知道,处理耗时任务不能放在主线程,比如网络请求、读写数据库。以前常用Handler、AsyncTask,代码绕来绕去,回调嵌一层又一层,看得人头疼。自从Kotlin协程上手后,这些问题轻松解决了。
协程不是线程,也不是替代线程的东西,它是一种更轻量的并发方案。你可以把它理解成“可暂停的函数”,在Android里用来处理异步任务特别顺手。
在项目中怎么开始用协程?
先在app的build.gradle加上依赖:
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'然后就可以在Activity或ViewModel里用了。最常用的场景就是从网络拉数据更新UI,比如你做个天气App,点一下刷新按钮,要发请求拿最新气温。
一个实际例子:请求数据并更新界面
假设你有个Repository负责获取用户信息:
class UserRepository {
suspend fun getUser(): User {
delay(2000) // 模拟网络延迟
return User("张三", 28)
}
}在ViewModel里启动协程调用它:
class MainViewModel : ViewModel() {
private val repository = UserRepository()
fun fetchUser() {
viewModelScope.launch {
try {
val user = repository.getUser()
// 更新LiveData,UI自动刷新
_user.value = user
} catch (e: Exception) {
_error.value = e.message
}
}
}
}这里viewModelScope是官方提供的作用域,Activity销毁时会自动取消协程,不用担心内存泄漏。
主线程安全是怎么做到的?
Kotlin协程默认运行在主线程,你可以在launch里直接更新TextView,不需要像以前那样切回主线程。
如果某个操作很耗CPU,比如解析大Json或压缩图片,可以用withContext切换调度器:
val result = withContext(Dispatchers.IO) {
parseHugeJson(data)
}
_processedData.value = resultDispatchers.IO适合磁盘和网络操作,Dispatchers.Default适合计算密集型任务,主线程就留给UI响应。
多个请求想一起等怎么办?
比如你要同时加载用户信息和订单列表,等两个都回来再刷新页面,可以用async配合awaitAll:
viewModelScope.launch {
try {
val userDeferred = async { repository.getUser() }
val orderDeferred = async { repository.getOrders() }
val (user, orders) = awaitAll(userDeferred, orderDeferred)
_userData.value = user
_orderData.value = orders
} catch (e: Exception) {
_error.value = e.message
}
}async返回的是Deferred对象,相当于一个未来会完成的任务,awaitAll会等所有任务结束再继续。
小贴士:避免常见的坑
别在普通函数里随便写suspend,除非它真需要挂起。协程虽然好用,但滥用也会让逻辑变乱。
还有,别忘了异常处理。协程里的异常不会自动抛到主线程,try-catch要自己加,尤其是网络请求这种容易出错的操作。
最后一点,测试协程时记得用TestDispatcher,不然可能遇到超时问题。