kotlin协程Flow的StateFlow和SharedFlow(十二)

32 篇文章 2 订阅

一、前言

有时候我们需要实时监听一个状态变化或者持续不断接收数据,Flow提供了StateFlowSharedFlow以供我们使用。两者的区别是StateFlow只能监听一个数据,针对的是单个数据的改变,适用于状态监听。SharedFlow是对数据流的监听,对于某一连串的事件的监听

二、使用方式

这里记录少部分注意事项,更多的使用方式,官方已经说明了。其中StateFlow会自动过滤重复数据,假如第二次发送的数据和第一次一样,那么第二次数据是收不到的,SharedFlow则不会如此

1、StateFlow

SharedFlowFlow的实现,StateFlowSharedFlow的实现。不同于Flow,数据使用完就关闭了,因为StateFlowSharedFlow是用来监听状态的,所以需要手动关闭。但是又由于Flow需要依托与协程,所以协程取消后,流会自动关闭,这里演示如下:

class ExampleUnitTest {
	private val _counter = MutableStateFlow(0)
    val counter = _counter.asStateFlow()
       @Test
    fun addition_isCorrect() {
        simpleStateFlow()
    }
    private fun simpleStateFlow(){
       private fun simpleStateFlow(){
        runBlocking {
            val job = launch {
                counter.collect{
                    println("YM---->value:$it")
                }

            }
            _counter.update{
                it + 1
            }
            delay(100)
            _counter.update{
                it + 1
            }
            delay(100)
            _counter.update{
                it + 1
            }
            delay(100)
            launch {
                delay(5000)
                job.cancel()
                println("YM---->cancel")
            }
        }
    }
    }
}

这是个单元测试,如果不执行cancel的话,会发现程序一直在运行,虽然已经不再发送消息。

2、SharedFlow

共享流的用法大题和上述一样,区别是发送数据的方式

class ExampleUnitTest {
    private val _counter = MutableSharedFlow<Int>(0)
    val counter = _counter.asSharedFlow()
    @Test
    fun addition_isCorrect() {
        simpleStateFlow()
    }
	private fun simpleStateFlow(){
        runBlocking {
            val job = launch {
                counter.collect{
                    println("YM---->value:$it")
                }

            }
            delay(100)
            _counter.emit(3)
            delay(100)
            _counter.emit(4)
            delay(100)
            launch {
                delay(5000)
                job.cancel()
                println("YM---->cancel")
            }
        }
    }
}

可以看到SharedFlowStateFlow最大的区别是,一个是发送不同的数据,一个是针对一个数据的改变。

3、replay

在创建对象的时候会可以传一个值,默认是0

   private val _counter = MutableSharedFlow<Int>()
   //等于下面写法
   private val _counter = MutableSharedFlow<Int>(0)

这个值的意思是缓冲数量,故名思义就是,如果没有被消耗就缓冲多少个数量的值。测试方式如下,先进行发送数据,后进行订阅数据,

 private val _counter = MutableSharedFlow<Int>(0)
    val counter = _counter.asSharedFlow()
private fun simpleStateFlow(){
        runBlocking {
            val job = launch {
                delay(10)
                counter.collect{
                    println("YM---->value:$it")
                }

            }
//            delay(100)
            _counter.emit(3)
            delay(100)
            _counter.emit(4)
            delay(100)
            launch {
                delay(5000)
                job.cancel()
                println("YM---->cancel")
            }
        }
    }

会发现3这个值是无法打印的,如果修改为 private val _counter = MutableSharedFlow<Int>(1)时候,这个值就可以打印了,缓冲的意思就是这个

4、stateIn、shareIn

如果已经有一个流了,可以将其转换为热流。方式如下

val coldFlow: Flow<Int> =  val coldFlow: Flow<Int> = (0..9).asFlow()

val shareFlow = coldFlow.shareIn(lifecycleScope, SharingStarted.Eagerly)
val stateFlow1 = coldFlow.stateIn(lifecycleScope, SharingStarted.Eagerly,
                CompletableDeferred<StateFlow<Int>>()
            )
private fun lifecycleListener(){
        lifecycleScope.launch {
			val stateFlow2 = coldFlow.stateIn(this)
        }
    }         

SharingStarted有两个参数:

 public val Eagerly: SharingStarted = StartedEagerly() //立即启用

        /**
         * Sharing is started when the first subscriber appears and never stops.
         */
public val Lazily: SharingStarted = StartedLazily() //延迟启用

CompletableDeferred是一个Deferred–一个轻量级的非阻塞 future, 这代表了一个将会在稍后提供结果的 promise。你可以使用 .await() 在一个延期的值上得到它的最终结果, 但是 Deferred 也是一个 Job,所以如果需要的话,你可以取消它。解释来自kotlin网站
CompletableDeferred可以保证从内到外的取消i个异步协程,如果使用job.cancelAndJoin()的话会阻塞线程池代码(该问题需未验证)。参考代码
https://stackoverflow.com/questions/52774588/coroutinescope-completabledeferred-cancellation

三、注意事项

使用StateFlowSharedFlow的时候需要注意生命周期,如果热流不会随着生命周期自动取消,也就是说页面消失后还会继续监听数据,或者下次进入时候会重复绑定,这样就会导致很多无法预料的错误。解决方案参考以下链接:

四、参考链接

  1. StateFlow
    https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-state-flow/

  2. StateFlow 和 SharedFlow
    https://developer.android.google.cn/kotlin/flow/stateflow-and-sharedflow?hl=zh-tw

  3. 协程之StateFlow和SharedFlow介绍
    https://www.kotliner.cn/2020/11/1-4-0%e5%8d%8f%e7%a8%8b%e4%b9%8bstateflow%e5%92%8csharedflow%e4%bb%8b%e7%bb%8d/

  4. 就几行代码?! 用SharedFlow写个FlowEventBus
    https://blog.csdn.net/vitaviva/article/details/118854626

  5. 关于 Flow 的 shareIn 和 stateIn 运算符的注意事项
    https://medium.com/androiddevelopers/things-to-know-about-flows-sharein-and-statein-operators-20e6ccb2bc74

  6. 生命周期感知型协成程
    https://mp.weixin.qq.com/s/tqNLTbBB2o4O_vLlAbf8hw

  7. 协程与架构组件一起使用
    https://developer.android.google.cn/topic/libraries/architecture/coroutines

  8. 组合挂起函数

  9. CoroutineScope - CompletableDeferred 取消

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值