可以查看代码示例(https://github.com/wangchongwei/JetpackLearn/tree/master/app/src/main/java/com/justin/jetpacklearn/Flow)

flow 数据流

Flow 库是在 Kotlin Coroutines 1.3.2 发布之后新增的库。

Flow只能运行在协程之中

Flow基本使用

Flow 能够返回多个异步计算的值,例如下面的 flow builder :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fun flow1() = runBlocking {
val time = measureTimeMillis {
flow {
for (i in 1..5) {
delay(100)
emit(i)
}
}.collect{
delay(100)
println("flow collect => $it")
}
}
println("time => $time")
}

注意:flow、collect是同步允许,总共会阻塞1000ms

冷流

冷流: 只有当订阅者发起订阅时,事件的发送者才会开始发送事件。

同步非阻塞

热流

热流:不管订阅者是否存在,flow本身可以调用emit(或者tryEmit)发送事件,可以有多个观察者,也可在需要的时候发送事件。
异步非阻塞

常用的热流有:

  • ChannelFlow
  • StateFlow
  • SharedFlow

ChannelFlow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fun channelFlow1() = runBlocking {
val time = measureTimeMillis {
channelFlow {
for (i in 1..5) {
delay(100)
send(i)
}
}.collect {
delay(100)
println("channelFlow collect => $it")
}
}
println("time => $time")
}

channelFlow 与 collect是异步的,当send只会,collect不会阻塞后续的send,
所以总共会阻塞600ms

StateFlow

StateFlow 是一个状态容器式可观察数据流,可以向其收集器发出当前状态更新和新状态更新。

一般用于MVI开发模式中,使用场景、方式都与 LiveData 类似,

查看示例:https://github.com/wangchongwei/JetpackLearn/tree/master/app/src/main/java/com/justin/jetpacklearn/mvi

用法如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class LoginViewModel @Inject 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
2
3
4
5
6
7
8
9
10
11
12
13
14
private var uiStateJob: Job? = null

private fun observeViewModelState() {
uiStateJob = lifecycleScope.launch {
viewModel.state.collect {
....
}
}
}

override fun onStop() {
uiStateJob?.cancel()
super.onStop()
}

在stop生命周期中,手动取消,但感觉此中方式麻烦且不优雅,
不如直接将 StateFlow 换为 LiveData ,
或者使用 lifecycleScope.launchWhenStarted 开启协程
避免这个问题

SharedFlow

和 StateFlow 一样,SharedFlow 也是热流,它可以将已发送过的数据发送给新的订阅者,并且具有高的配置性。

SharedFlow 使用场景
  • 发生订阅时,需要将过去已经更新的n个值,同步给新的订阅者。
  • 配置缓存策略。