StateFlow与SharedFlow(一)

简介

因作者语文不好,就不进行繁琐的介绍了.如果照抄其他文章或者官方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是提交状态而非事件.下次再说

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值