我在android开发中断断续续也使用到了协程,之前都是基于能用,但没有深究,导致每次使用都是机械调用。这次得空 看着官网学习学习,简单记录一下。 附上官网地址:https://developer.android.google.cn/kotlin/coroutines?hl=zh-cn#features
协程是一种并发设计模式,您可以在 Android 平台上使用它来简化异步执行的代码。
简单来说就是可以用它来执行异步的一些操作,优雅的写代码。
场景:界面上有一个按钮,点击之后调用请求网络,通过ViewModel的方法执行,获取到数据之后在更新到界面的一个文本。这个开发中最普遍的 一个使用场景。
原来的操作中会在点击之后调用三方的网络请求执行在IO线程中,最后请求到了数据后,通过LiveData 等 再更新到UI界面
现在的操作是 在viewModel中
class TestViewModel : ViewModel() {
fun requestHttp(){
//开启协程
viewModelScope.launch {
val value = doSomeing()
//更新UI
}
}
private suspend fun doSomeing():String {
//模拟耗时
delay(6000)
retutn "结果"
}
}
自己不用单独开线程执行,直接调用协程处理,至于更新UI,可以使用
StateFlow 或者 SharedFlow
StateFlow 状态持有者 始终有值
SharedFlow 事件发射器 每次发送新的
两种都可以用来更新UI使用,看场景区分 StateFlow总是会有一个值,随时可以获取,SharedFlow有点像到点执行,错过就没有了。
1:StateFlow
private val _uiState = MutableStateFlow(LatestNewsUiState.Success(emptyList()))
val uiState: StateFlow<LatestNewsUiState> = _uiState
_uiState.value = LatestNewsUiState.Success(favoriteNews) //viewModel发送
repeatOnLifecycle(Lifecycle.State.STARTED) { //界面中接收
latestNewsViewModel.uiState.collect { uiState ->
// New value received
when (uiState) {
is LatestNewsUiState.Success -> showFavoriteNews(uiState.news)
is LatestNewsUiState.Error -> showError(uiState.exception)
}
}
}
2:SharedFlow
private val _tickFlow = MutableSharedFlow<Unit>(replay = 0)
val tickFlow: SharedFlow<Unit> = _tickFlow
_tickFlow.emit(Unit) //viewModel 发送
tickHandler.tickFlow.collect { //界面接收
refreshLatestNews()
}
Dispatchers的浅见
通过协程调用方法中
viewModelScope.launch {
// 默认在 Dispatchers.Main 上启动
val result = getUsers() // 挂起函数,自动切换IO
updateUI(result) // 直接在主线程更新UI
}
直接在方法体中顺序执行下来,很优雅
viewModelScope.launch(Dispatchers.IO) {
// 在IO线程池启动
val result = getUsers() // 挂起函数
// 不能直接更新UI!
withContext(Dispatchers.Main) {
updateUI(result) // 需要切回主线程
}
}
也可以自己切换IO,但是最终需要切换Main 更新UI
launch 和 async 区别
// 基本用法 launch
viewModelScope.launch {
// 执行一些操作
analytics.log(event) // 不关心结果
}
// 基本用法 async
viewModelScope.launch {
// 启动异步任务
val deferred: Deferred<String> = async {
fetchData() // 返回 String
}
// 等待执行结果
val result: String = deferred.await()
}
自定定义作用域
class ExampleClass {
//自己也可以创建作用域,但是要记得及时清理
val scope = CoroutineScope(Job() + Dispatchers.Main)
fun exampleMethod() {
scope.launch {
fetchDocs()
}
}
fun cleanUp() {
scope.cancel()
}
}