一、前言
当下 Android 比较流行的架构是 MVI + Kotlin 协程 + Compose,在 MVI 的架构中。为了减少 LiveData 在复杂页面过多的问题,我们推荐使用 State 进行统一管理。
LiveData 是 UI Layer 所观察的对象,在页面销毁的时候,能够自动取消所有的观察者,避免内存泄漏。和 LiveData 相比, Flow具有如下优势:
- 支持背压
- 支持数据变换
- 支持线程切换
总之一句话,Flow 天生为协程而生。
二、流的分类
Kotlin 的流可以分为两类,冷流和热流。冷流和热流的区别如下:
冷流:没有消费者,生产者就不会生产数据。
热流:是否生产数据,和消费者没有关系
在 Kotlin 协程中,Flow 是冷流,StateFlow、SharedFlow、Channel 等是热流。StateFlow 用于页面状态,SharedFlow 用于事件,Channel 主要用于协程间进行通信。
三、flow、channel 的用法
flow 的用法如下:
// ViewModel
fun getData(): Flow<String> = flow {
emit("")
}.flowOn(Dispatchers.IO).catch {
println(it.message)
}
// Activity
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
vm.getData().collect {}
}
}
StateFlow 和 SharedFlow用法如下:
private val _stateFlow = MutableStateFlow(1)
val stateFlow: StateFlow<Int> = _stateFlow
private val _shareFlow = MutableSharedFlow<Int>()
val shareFlow : SharedFlow<Int> = _shareFlow
viewModelScope.launch {
_stateFlow.value = 2
_shareFlow.emit(1)
}
Channel 主要是用在协程之间进行通信,代码示例如下:
fun main() = runBlocking {
GlobalScope.launch {
val channel = Channel<Int>()
val scope = CoroutineScope(Job())
scope.launch {
launch {
channel.send(1)
}
launch {
println(channel.receive())
}
}.join()
}.join()
}
Flow 还有其他的一些操作变换符,例如 map、tranform 等,不在这里一一详述。另外,Channel 是线程安全的。
四、需要注意什么
LiveData 和 StateFlow 在 Android 架构中,都是用于状态更新的,他们区别如下:
- LiveData 具有生命周期感知的能力,StateFlow 不具备,因此 StateFlow监听数据的时候,需要在生命周期里
- LiveData 不具备防抖的能力,StateFlow 具有防抖的能力
SharedFlow 和 StateFlow 都是热流,StateFlow 是特殊 SharedFlow,他们的区别如下:
- 从作用场景来看,SharedFlow 用于事件更新,StateFlow 用于状态更新
- collect() 和 emit() 都是挂起函数,需要确保在协程内部进行调用
- SharedFlow emit() 和collect() 都是挂起函数,可能会阻塞当前的协程。因此生产者和消费者需要需要在不同的协程。