美文网首页
使用ChannelFlow实现单次事件流

使用ChannelFlow实现单次事件流

作者: 头秃到底 | 来源:发表于2024-03-20 17:51 被阅读0次

发现在项目里还存在一些业务场景,需要实现的是单次响应事件,使用的却是SharedFlow/StateFlow,导致部分场景下事件会丢失或多次响应。

在Flow之前有SingleEventLiveData实现单次事件流,而Flow自身却并未直接类似的方法。 作为功能更为优雅全面的Flow,不可能没有相关的实现。

于是在搜寻一番后发现了ChannelFlow这个东西,可以简单好用地实现单次事件流

使用方法

private val _eventChannel = Channel<HomeTabEvent>(capacity = Channel.CONFLATED)
val eventFlow = _eventChannel.receiveAsFlow()

// 发送方
fun sendEvent(event: HomeTabEvent) {
    viewModelScope.launch {
        _eventChannel.send(event)
    }
}

// 接收方
lifecycleScope.launch {
    activity.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.eventFlow.collect {
            ...
        }
    }
}

使用方法与SharedFlow基本相似

在初始化变量时设置capacity = Channel.CONFLATED,保证数据池里仅有一位最新的有效值,在接收端只会收到最新的值,并且在接收到数据后把数据池清掉,让事件不会重复响应

效果上与SingleEventLiveData相似

对比SharedFlow

SharedFlow是热流,意思是数据是由发送方自己完成的,不依赖于接收方。

因此当事件A发送时,接收方B如果还没开始订阅,数据就已经存到数据池里。当B开始订阅后,也不会再收到历史事件A,有可能导致丢失了事件A的处理操作。

对此情况SharedFlow提供了replay参数的设置选项,通过设置replay=n,可以让新的订阅者接收到n个历史消息事件。

public fun <T> MutableSharedFlow(
    replay: Int = 0,
    extraBufferCapacity: Int = 0,
    onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND
): MutableSharedFlow<T> 

当设置replay=1,可以让新的订阅者接收到之前发送的事件,看起来解决了上述的问题。

然而。。设置了replay后也引来了新的问题,或者说replay机制如此产生的新效应,那就是可能导致重复处理同一个事件。

通常我们在Activity/Fragment订阅事件的方式如下:

lifecycleScope.launch {
    lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.sharedFlow.collect {
            //...
        }
    }
}

但是当页面状态发生变化,重新走到订阅流程时,就会触发replay的历史事件,又做了一次事件处理操作。

因此有一些地方为了解决此问题做了一些标志判断,比如:

lifecycleScope.launch {
    lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.sharedFlow.collect {
            if (isHandled) {
                return
            }
            isHandled = true
            //...
        }
    }
}

最后也能用,就是流程和写法上过于多余,不如直接使用ChannelFlow。

总结

  • 对于单次事件流,使用ChannelFlow替换StateFlow/SharedFlow更为简单且方便
  • 用SharedFlow来实现单次稳定可靠的事件流,无论设不设置replay=1,都存在使用上的问题,而ChannelFlow可以避免这些问题
  • ChannelFlow有着数据线程安全,单次事件稳定的优势,可以完美替换SingleEventLiveData

虽然在单次事件场景上SharedFlow有着一些局限性,但它依然在许多场景中有着很好的表现,它的历史回报、背压机制在很多数据流场景中都能满足。

归根到底,无论是Channel还是Flow,都是机制固定的数据流工具,作为开发者应该去了解它们的机制和原理,更好地根据业务场景去使用它们。服务于业务,保证业务的稳定可靠才是最重要。当然,关键的是优雅 优雅!

相关文章

  • 事件

    本章内容:理解事件流、使用事件处理程序、不同的事件类型 JavaScript与HTML之间的交互是通过事件实现的。...

  • 事件捕获和事件冒泡

    因为兼容ie,一般使用事件冒泡 事件 js和浏览器交互通过事件实现 事件流 页面元素接受事件的顺序 事件捕获 从根...

  • 事件

    事件 javaScript 与 HTML 之间的交互是通过事件实现的 1.事件流 (1)事件冒泡 IE 的事件流叫...

  • JS事件冒泡与捕获(addEventListener)

    1、事件传播——冒泡与捕获 默认情况下,事件使用冒泡事件流,不使用捕获事件流。然而,在Firefox和Safari...

  • 事件

    js 和html 之间的交互是通过事件实现的。 事件流:页面接收事件的顺序, dom事件流:事件捕获, 事件目标阶...

  • iOS 单例

    单例模式实现不能使用继承 定义单例实现 简写 定义单例实现宏

  • 使用Nginx实现简单的RTMP推流直播笔记

    实现结果 推流的实现:使用OBS Studio进行推流拉流播放的实现:使用VLC进行拉流地址播放直播服务器实现:c...

  • js事件

    参考链接: 1.参考链接1 javaScript 与 HTML 之间的交互是通过事件实现的 事件流:事件流描述的是...

  • Python实现单例模式

    1.使用__new__实现 2.使用装饰器实现单例 3.类装饰器实现单例 4.元类实现

  • 浏览器兼容事件处理程序

    掌握要点:1、理解事件流2、使用事件处理程序3、不同的事件类型 一、事件流事件流描述的是从页面中接受事件的顺序。I...

网友评论

      本文标题:使用ChannelFlow实现单次事件流

      本文链接:https://www.haomeiwen.com/subject/ncixtjtx.html