kotlin (二)
flow 数据流
Flow 库是在 Kotlin Coroutines 1.3.2 发布之后新增的库。
Flow只能运行在协程之中
Flow基本使用
Flow 能够返回多个异步计算的值,例如下面的 flow builder :
1 | fun flow1() = runBlocking { |
注意:flow、collect是同步允许,总共会阻塞1000ms
冷流
冷流: 只有当订阅者发起订阅时,事件的发送者才会开始发送事件。
同步非阻塞
热流
热流:不管订阅者是否存在,flow本身可以调用emit(或者tryEmit)发送事件,可以有多个观察者,也可在需要的时候发送事件。
异步非阻塞
常用的热流有:
- ChannelFlow
- StateFlow
- SharedFlow
ChannelFlow
1 | fun channelFlow1() = runBlocking { |
channelFlow 与 collect是异步的,当send只会,collect不会阻塞后续的send,
所以总共会阻塞600ms
StateFlow
StateFlow 是一个状态容器式可观察数据流,可以向其收集器发出当前状态更新和新状态更新。
一般用于MVI开发模式中,使用场景、方式都与 LiveData 类似,
用法如下所示1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20class LoginViewModel constructor(private var repository: LoginRepository): BaseViewModel() {
val userIntent = Channel<LoginIntent>(Channel.UNLIMITED)
private val _state = MutableStateFlow<LoginState>(LoginState.Idle)
val state: StateFlow<LoginState>
get() = _state
}
class MVIActivity : AppCompatActivity() {
lifecycleScope.launch {
// 当state状态变更时
viewModel.state.collect {
when(it) {
.....
}
}
}
}
StateFlow 与 LiveData 区别
有两点区别
- StateFlow 必须有初始值,LiveData 不需要。
- 当 View 变为 STOPPED 状态时,LiveData.observe() 会自动取消注册使用方,而从 StateFlow 或任何其他数据流收集数据则不会取消注册使用方。
对于 StateFlow 在界面销毁的时仍处于活跃状态,有两种解决方法:
- 使用 ktx 将 Flow 转换为 LiveData。
- 在界面销毁的时候,手动取消(这很容易被遗忘)。
- 使用 lifecycleScope.launchWhenStarted 开启协程
1 | private var uiStateJob: Job? = null |
在stop生命周期中,手动取消,但感觉此中方式麻烦且不优雅,
不如直接将 StateFlow 换为 LiveData ,
或者使用 lifecycleScope.launchWhenStarted 开启协程
避免这个问题
SharedFlow
和 StateFlow 一样,SharedFlow 也是热流,它可以将已发送过的数据发送给新的订阅者,并且具有高的配置性。
SharedFlow 使用场景
- 发生订阅时,需要将过去已经更新的n个值,同步给新的订阅者。
- 配置缓存策略。