在 Android 开发中,Kotlin 协程是处理异步操作的首选方案,它能让异步代码更简洁、更易读。以下是 Android 协程异步编程的常用方法和模式:
viewModelScope.launch {
// 默认在主线程执行
updateUI()
// 切换到 IO 线程执行耗时操作
withContext(Dispatchers.IO) {
saveDataToDisk()
}
}
Deferred
对象,通过 await()
获取结果。viewModelScope.launch {
val task1 = async(Dispatchers.IO) { fetchDataFromNetwork() }
val task2 = async(Dispatchers.IO) { loadCacheFromDisk() }
// 等待两个任务完成并合并结果
val result = combine(task1.await(), task2.await())
updateUI(result)
}
viewModelScope.launch {
// 主线程:显示加载状态
showLoading()
// 切换到 IO 线程执行耗时操作
val data = withContext(Dispatchers.IO) {
repository.fetchData()
}
// 自动回到主线程:更新 UI
updateUI(data)
}
调度器 | 作用 | 适用场景 |
---|---|---|
Dispatchers.Main | 主线程,用于 UI 操作 | 更新 TextView、启动动画 |
Dispatchers.IO | 后台线程,优化磁盘 / 网络 IO | 文件读写、网络请求 |
Dispatchers.Default | 后台线程,用于 CPU 密集型任务 | 复杂计算、JSON 解析 |
Dispatchers.Unconfined | 不指定固定线程,由调用者决定 | 测试、初期协程启动 |
class MyViewModel : ViewModel() {
fun fetchData() {
// 使用 viewModelScope,Activity/Fragment 销毁时自动取消
viewModelScope.launch {
val data = withContext(Dispatchers.IO) {
repository.loadData()
}
_liveData.value = data
}
}
}
private var job: Job? = null
fun startTask() {
job = viewModelScope.launch {
// 执行耗时操作
}
}
fun cancelTask() {
job?.cancel() // 手动取消协程
}
viewModelScope.launch {
try {
val result = withContext(Dispatchers.IO) {
api.fetchData() // 可能抛出异常的操作
}
updateUI(result)
} catch (e: IOException) {
showError(e.message)
}
}
// 从数据库获取实时数据
fun getUserFlow(): Flow<User> = flow {
while (true) {
emit(database.getUser()) // 发送数据
delay(1000) // 每秒更新一次
}
}.flowOn(Dispatchers.IO) // 指定流的执行线程
// 在 ViewModel 中收集
viewModelScope.launch {
userFlow.collect { user ->
_liveData.value = user // 更新 LiveData
}
}
StateFlow:保存最新值的热流,适合表示状态。
// ViewModel 中
private val _uiState = MutableStateFlow<UiState>(Loading)
val uiState: StateFlow<UiState> = _uiState
// 协程中更新状态
_uiState.value = Success(data)
SharedFlow:更灵活的热流,可配置重放次数、缓冲区大小。
private val _event = MutableSharedFlow<Event>()
val event: SharedFlow<Event> = _event
// 发送事件
viewModelScope.launch {
_event.emit(ToastEvent("操作成功"))
}
val channel = Channel<String>()
// 生产者协程
viewModelScope.launch {
repeat(5) {
delay(1000)
channel.send("消息 $it")
}
channel.close() // 发送完毕后关闭
}
// 消费者协程
viewModelScope.launch {
for (msg in channel) {
Log.d("Channel", "收到: $msg")
}
}
viewModelScope.launch {
val user = withContext(Dispatchers.IO) { api.getUser() }
val orders = withContext(Dispatchers.IO) { api.getOrders(user.id) }
updateUI(orders)
}
viewModelScope.launch {
val userDeferred = async(Dispatchers.IO) { api.getUser() }
val ordersDeferred = async(Dispatchers.IO) { api.getOrders(userId) }
val user = userDeferred.await()
val orders = ordersDeferred.await()
updateUI(user, orders)
}
zip
合并流val flow1 = flow { emit(1) }
val flow2 = flow { emit("A") }
// 合并两个流的结果
flow1.zip(flow2) { num, str -> "$num-$str" }
.collect { result -> Log.d("Zip", result) } // 输出 "1-A"
// 将 Flow 转换为 LiveData
val liveData: LiveData<User> = flow {
emit(repository.getUser())
}.flowOn(Dispatchers.IO)
.asLiveData()
// DAO 方法返回 Flow
@Query("SELECT * FROM users")
fun getUsers(): Flow<List<User>>
// ViewModel 中收集数据
viewModelScope.launch {
userDao.getUsers().collect { users ->
_usersLiveData.value = users
}
}
通过合理使用上述方法,你可以在 Android 中编写简洁、高效且安全的异步代码,避免回调地狱和内存泄漏问题。
Copyright © 2019- zgxue.com 版权所有 京ICP备2021021884号-5
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务