https://www.youtube.com/watch?v=6Jc6-INantQ
学习笔记
在viewmodel中定义三个数据,确保只在内部进行修改,暴露只读的给外部监听
private val _livedata = MutableLiveData("hello")
val liveData: LiveData<String> = _livedata
private val _stateFlow = MutableStateFlow("hello")
val stateFlow = _stateFlow.asStateFlow()
private val _sharedFlow = MutableSharedFlow<String>()
val sharedFlow = _sharedFlow.asSharedFlow()
对应不同的按钮触发数据更改
fun triggerLiveData() {
_livedata.value = "livedata"
}
fun triggerStateFlow() {
_stateFlow.value = "stateflow"
}
fun triggerFlow(): Flow<String> {
return flow {
repeat(5) {
emit("item $it")
delay(1000)
}
}
}
fun triggerSharedFlow(){
viewModelScope.launch {
_sharedFlow.emit("SharedFlow")
}
}
livedata 和 stateflow比较像,可以hold value,所以初始化的时候,都有传入默认的值
shareflow 和 flow 更像是事件,没有holdvalue
大部分情况下,对于UI的内容,我们使用stateflow比较多
Stateflow是热流,没有订阅者的话,也是会发送事件,然后flow还有很多操作组合等。
另外,当界面横竖屏切换的时候,因为stateflow可以hole值,所以内容还在
Shareflow 和stateflow一样,属于热流,但是Shareflow不会存值,所以横竖屏切换后,之前的值不在了,不会引发事件和更改。所以更适合做消息弹窗
flow是普通的流,是冷流,所以只有当订阅的时候,才开始发送事件,所以当触发triggerFlow的时候我们可以看到数据的发送过程,从0~4,监听到数据变化了,更新textview,当界面切换后,又回到原始的
private fun subscribeData() {
mainViewModel.liveData.observe(this) {
binding.txtTest.text = it
}
lifecycleScope.launchWhenStarted {
mainViewModel.stateFlow.collectLatest {
//旋转界面值还在
binding.txtTest.text = it
//切换界面的时候,回重复出现,因为stateFlow可以缓存值,重新创建会发送
Snackbar.make(binding.root,
it,
Snackbar.LENGTH_LONG)
.show()
}
}
lifecycleScope.launchWhenStarted {
mainViewModel.sharedFlow.collectLatest {
//旋转界面,值不在了,因为 sharedFlow 没有存储值
binding.txtTest.text = it
//旋转切换界面,不会重复弹出,除非再次触发emit
Snackbar.make(binding.root,
it,
Snackbar.LENGTH_LONG)
.show()
}
}
}
private fun onButtonClick(){
lifecycleScope.launch {
mainViewModel.triggerFlow().collectLatest {
binding.txtTest.text = it
//点击按钮,会0-4的变化,然后停止,但是界面切换之后,恢复到hello
}
}
}
private fun onButtonClick2(){
mainViewModel.triggerSharedFlow()
}
在加一个stateflow 和Shareflow的对比
private val _sharedFlow = MutableSharedFlow<String>()
val sharedFlow = _sharedFlow.asSharedFlow()
fun triggerStateFlow() {
_stateFlow.value = "stateflow"
}
fun triggerSharedFlow(value:Int){
viewModelScope.launch {
_sharedFlow.emit("SharedFlow $value")
}
}
fun collectShareFlow(){
triggerSharedFlow(1)
viewModelScope.launch {
//这里用collect 而不是 collectLatest
//因为我们不想丢失事件
sharedFlow.collect{
delay(1000)
println("sharedFlow: 1 received $it")
}
}
triggerSharedFlow(2)
viewModelScope.launch {
sharedFlow.collect{
delay(2000)
println("sharedFlow: 2 received $it")
}
}
triggerSharedFlow(3)
}
发送了三次时间1、2、3,
1 实在两个订阅之前,2实在两个订阅之间,3 是在两个订阅之后
1 两个订阅都没有收到,因为Shareflow是热流,即使没有订阅也会发送事件,所以在两个订阅开始之前,这个事件就丢失了
2.是在1订阅之后,所以1收到到事件2,
3是在两个订阅之后的,所以两个订阅都收到到了3