概述
简介
因作者语文不好,就不进行繁琐的介绍了.如果照抄其他文章或者官方api也没有意义
可以简单理解为StateFlow和SharedFlow都是Flow的子类.
区别是,Flow是冷流,没有订阅者可以理解为他不保存数据,你在订阅之前的数据无法接收.
而StateFlow和SharedFlow是热流,创建的时候就已经在可以保存数据了.
简单来说 StateFlow和SharedFlow都可以监听数据的变化
类似LiveData的使用
下面直接上干货
准备工作:
implementation ("org.jetbrains.kotlinx:kotlinx-coroutines-core:$vserion") implementation ("org.jetbrains.kotlinx:kotlinx-coroutines-android:$vserion")
StateFlow简单使用
首先.需要在创建一个StateFlow
最简单的:
val stateFlow: StateFlow<Int>
那们我们已经完成第一步,申明一个StateFlow的变量,他是Int型的.
接下来我们给他复制一个初始值,
这里要注意一下,StateFlow是必须要给初始值的,如果对象定义的是T?,可以赋值为null
val stateFlow: StateFlow<Int> = MutableStateFlow(1)
这样 就完成了一个Int型stateFlow的创建.
其实这种写法是不好的,下面贴一下StateFlow的推荐创建方式
val stateFlow: StateFlow<Int> get() = stateFlowImpl
private val stateFlowImpl = MutableStateFlow(1)
为啥要这么写?后面会做讲解
接下来完成StateFlow的使用吧
其实没啥好说的 直接上代码
//创建一个协程作用域
private val scope = CoroutineScope(Dispatchers.Default)
//创建stateFlow对象
val stateFlow: StateFlow<Int> get() = stateFlowImpl
private val stateFlowImpl = MutableStateFlow(1)
private fun print(){
//监听stateFlow值的变化
scope.launch {
stateFlow.collect {
Log.d(TAG, "print: it = $it")
}
//切记 stateFlow的collect方法是个死循环,
//所以下面任何代码都不会执行,想取消监听则取消这个job即可
}
}
这样 我们就完成了对stateFlow数据变化监听
且看运行结果
D/DaComing: print: it = 1
很明显,collect的时候就监听到了数据为1
即初始值
那如何对stateFlow进行数据的改变呢?
使用flow.emit方法即可
//创建一个协程作用域
private val scope = CoroutineScope(Dispatchers.Default)
//创建stateFlow对象
val stateFlow: StateFlow<Int> get() = stateFlowImpl
private val stateFlowImpl = MutableStateFlow(1)
private fun emitData(){
scope.launch {
stateFlowImpl.emit(2)
}
}
private fun print(){
//监听stateFlow值的变化
scope.launch {
stateFlow.collect {
Log.d(TAG, "print: it = $it")
}
//切记 stateFlow的collect方法是个死循环,
//所以下面任何代码都不会执行,想取消监听则取消这个job即可
}
}
这样 我们就完成了stateFlow数据的提交
然后我们执行代码
执行顺序是
print()
emitData()
看打印
D/DaComing: print: it = 1
D/DaComing: print: it = 2
很简单,collect收到初始值1,然后emit 数值2后,监听到collect 2
当然你可以直接使用stateFlow里面的值
比如
print()
emitData()
lifecycleScope.launchWhenResumed {
Log.d(TAG, "value: ${stateFlow.value}")
}
看结果
D/DaComing: print: it = 1
D/DaComing: print: it = 2
D/DaComing: value: 2
这样,一旦上游有数据变化,下游就立马能收到数据监听,配合lifecycleScope既可以在activity活跃的时候collect数据,也可以在activity在后台的时候,进行数据变化.并且可以使用flow里面的值作为各种参数使用.功能比LiveData是要强大的.
以上就是StateFlow简单的使用
下面介绍下StateFlow的为什么叫StateFlow
StateFlow又称状态流,他只关心流的状态
举个栗子
不论上游发送了 emit 多少条数据 下游如果不处理完成,是不会收到collect的,
比如
private fun print(){
scope.launch {
stateFlow.collect {
//处理一次状态要100ms
Log.d(TAG, "print: it = $it")
delay(100)
}
}
}
private fun emitData(){
scope.launch {
for(i in 1..10){
//发送一次状态要20ms
stateFlowImpl.emit(i)
delay(20)
}
}
}
执行顺序
print() emitData()
运行结果
D/DaComing: print: it = 1
D/DaComing: print: it = 5
D/DaComing: print: it = 10
我们把emit的地方称为上游,collect之后的处理称之为下游
首先 刚collect 的时候,收到初始值为1的回调,下游处理需要100ms
而上游每20ms发送一次数据,当第一次下游在处理的时候,上游已经发送了五条数据,1,2,3,4,5
这样,当下游处理完成的时候,才会继续collect当前最新的emit值,也就是stateFlow里面的value值
所以,不论上游提交了多少条数据,下游还没处理完成的时候,是不会进行多余emit数据的处理的.
好像这个原理类似于背压,不管上游压力有多啊,下游的处理速度都是一样的.
也不用担心多线程的问题了
并且,stateFlow如果上游emit了与上一次相同的数据,即使下游是空闲的,下游collect也不会收到数据.
最后,解答一下为什么要
val stateFlow: StateFlow<Int> get() = stateFlowImpl
private val stateFlowImpl = MutableStateFlow(1)
这么写的原因
其实我也不太懂哈哈哈
官方这么建议的
不这么写也不会出错
但是 笔者个人的理解是
一般来说,StateFlow的下游的处理,都在view层,而在view层只负责对stateFlow的监听,
stateFlow可以collect而不能emit,只有stateFlowImpl可以emit数据
而StateFlow创建都是在数据处理层(用mvvm一半时viewmodel层),注意stateFlowImpl是private,
这样view层就无法直接参与数据的处理和交互,比较偏向于MVI?
MVI我也不太懂,但是感觉和MVVM大同小异,没有MVP和MVVM的差异大的感觉
那如果我每个事件都想要处理怎么办 StateFlow是会丢事件的啊
那么就要用上SharedFlow了.所以嘛,一般都是StateFlow是提交状态而非事件.下次再说
最后
以上就是暴躁季节为你收集整理的StateFlow与SharedFlow(一)的全部内容,希望文章能够帮你解决StateFlow与SharedFlow(一)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复