Loading [MathJax]/jax/output/CommonHTML/config.js
社区首页 >问答首页 >如何将项目发送到Kotlin.Flow (如行为主题)

如何将项目发送到Kotlin.Flow (如行为主题)
EN

Stack Overflow用户
提问于 2019-08-04 01:12:57
回答 3查看 22.1K关注 0票数 39

我想知道如何向Kotlin.Flow发送/发出项,所以我的用例是:

在使用者/视图模型/演示器中,我可以订阅collect函数:

代码语言:javascript
代码运行次数:0
复制
fun observe() {
 coroutineScope.launch {
    // 1. Send event
    reopsitory.observe().collect {
      println(it)
    }
  }
}

但是问题在Repository方面,对于RxJava,我们可以使用行为主体将其公开为Observable/Flowable,并发出如下所示的新项:

代码语言:javascript
代码运行次数:0
复制
behaviourSubject.onNext(true)

但是每当我建立一个新的流程:

代码语言:javascript
代码运行次数:0
复制
flow {

}

我只能收集。如何向流发送值?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-08-04 01:12:57

如果要获取订阅/集合的最新值,则应使用ConflatedBroadcastChannel

代码语言:javascript
代码运行次数:0
复制
private val channel = ConflatedBroadcastChannel<Boolean>()

这将复制BehaviourSubject,将通道公开为流:

代码语言:javascript
代码运行次数:0
复制
// Repository
fun observe() {
  return channel.asFlow()
}

现在,要向公开的Flow发送一个事件/值,只需向这个通道发送。

代码语言:javascript
代码运行次数:0
复制
// Repository
fun someLogicalOp() {
  channel.send(false) // This gets sent to the ViewModel/Presenter and printed.
}

控制台:

错误

如果您只希望在之后接收值,那么您应该使用BroadcastChannel代替。

为了表明这一点:

表现为Rx的PublishedSubject

代码语言:javascript
代码运行次数:0
复制
private val channel = BroadcastChannel<Boolean>(1)

fun broadcastChannelTest() {
  // 1. Send event
  channel.send(true)

  // 2. Start collecting
  channel
    .asFlow()
    .collect {
      println(it)
    }

  // 3. Send another event
  channel.send(false)
}

错误

只有false被打印出来,因为第一个事件是在 collect { }之前发送的。

表现为Rx的BehaviourSubject

代码语言:javascript
代码运行次数:0
复制
private val confChannel = ConflatedBroadcastChannel<Boolean>()

fun conflatedBroadcastChannelTest() {
  // 1. Send event
  confChannel.send(true)

  // 2. Start collecting
  confChannel
    .asFlow()
    .collect {
      println(it)
    }

  // 3. Send another event
  confChannel.send(false)
}

真的 错误

这两个事件都是打印出来的,您总是得到最新的值(如果有)。

此外,还想提到Kotlin在DataFlow上的团队开发(名称待定):

这似乎更适合这个用例(因为它将是一个冷流)。

票数 48
EN

Stack Overflow用户

发布于 2020-06-21 18:22:19

请看一看MutableStateFlow文档,因为它很快就将取代即将被废弃的ConflatedBroadcastChannel

要获得更好的上下文,请查看论柯特林在吉特卜上的存储库的原始问题

票数 20
EN

Stack Overflow用户

发布于 2020-05-13 13:18:06

更新

Kotlin 1.4.0现在可以与MutableSharedFlow一起使用,它取代了对Channel的需求。MutableSharedFlow清理也是内置的,所以您不需要手动打开和关闭它,不像Channel。如果需要类似主题的api for MutableSharedFlow,请使用Flow

原始答案

由于您的问题有android标记,我将添加一个Android实现,它允许您轻松地创建一个BehaviorSubject或一个处理自己生命周期的PublishSubject

这在Android中是相关的,因为您不想忘记关闭通道并泄漏内存。此实现避免了通过将反应性流与创建和销毁片段/活动绑定而显式“处置”该流的需要。类似于LiveData

代码语言:javascript
代码运行次数:0
复制
interface EventReceiver<Message> {
    val eventFlow: Flow<Message>
}

interface EventSender<Message> {
    fun postEvent(message: Message)
    val initialMessage: Message?
}

class LifecycleEventSender<Message>(
    lifecycle: Lifecycle,
    private val coroutineScope: CoroutineScope,
    private val channel: BroadcastChannel<Message>,
    override val initialMessage: Message?
) : EventSender<Message>, LifecycleObserver {

    init {
        lifecycle.addObserver(this)
    }

    override fun postEvent(message: Message) {
        if (!channel.isClosedForSend) {
            coroutineScope.launch { channel.send(message) }
        } else {
            Log.e("LifecycleEventSender","Channel is closed. Cannot send message: $message")
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun create() {
        channel.openSubscription()
        initialMessage?.let { postEvent(it) }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun destroy() {
        channel.close()
    }
}

class ChannelEventReceiver<Message>(channel: BroadcastChannel<Message>) :
    EventReceiver<Message> {
    override val eventFlow: Flow<Message> = channel.asFlow()
}

abstract class EventRelay<Message>(
    lifecycle: Lifecycle,
    coroutineScope: CoroutineScope,
    channel: BroadcastChannel<Message>,
    initialMessage: Message? = null
) : EventReceiver<Message> by ChannelEventReceiver<Message>(channel),
    EventSender<Message> by LifecycleEventSender<Message>(
        lifecycle,
        coroutineScope,
        channel,
        initialMessage
    )

通过使用Android的Lifecycle库,我现在可以创建一个BehaviorSubject,在活动/片段被销毁后清理它自己。

代码语言:javascript
代码运行次数:0
复制
class BehaviorSubject<String>(
    lifecycle: Lifecycle,
    coroutineScope: CoroutineScope,
    initialMessage = "Initial Message"
) : EventRelay<String>(
    lifecycle,
    coroutineScope,
    ConflatedBroadcastChannel(),
    initialMessage
)

或者我可以使用缓冲的PublishSubject创建BroadcastChannel

代码语言:javascript
代码运行次数:0
复制
class PublishSubject<String>(
    lifecycle: Lifecycle,
    coroutineScope: CoroutineScope,
    initialMessage = "Initial Message"
) : EventRelay<String>(
    lifecycle,
    coroutineScope,
    BroadcastChannel(Channel.BUFFERED),
    initialMessage
)

现在我可以做这样的事

代码语言:javascript
代码运行次数:0
复制
class MyActivity: Activity() {

    val behaviorSubject = BehaviorSubject(
        this@MyActivity.lifecycle,
        this@MyActivity.lifecycleScope
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (savedInstanceState == null) { 

            behaviorSubject.eventFlow
                .onEach { stringEvent ->
                    Log.d("BehaviorSubjectFlow", stringEvent)
                    // "BehaviorSubjectFlow: Initial Message"
                    // "BehaviorSubjectFlow: Next Message"
                }
                .flowOn(Dispatchers.Main)
                .launchIn(this@MyActivity.lifecycleScope)

        }
    }

    override fun onResume() {
        super.onResume()

        behaviorSubject.postEvent("Next Message")
    }
}
票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57345311

复制
相关文章
Java反射探索-----从类加载说起
林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka
bear_fish
2018/09/20
5220
Java反射探索-----从类加载说起
枚举帮助类
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Linq; 5 6 namespace EnumHelper 7 { 8 /// <summary> 9 /// 枚举帮助类 10 /// 1、获取枚举的描述文本 11 /// 2、获取枚举名和描述信息的列表 12 /// </summary> 13
用户6362579
2019/09/29
5380
日志帮助类
 1.代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Configuration; using System.Reflection; namespace LogHelper.Common { public class LogHelper { private string logFile
用户1055830
2018/01/18
6520
日志帮助类
从源码角度学习JVM类加载器及自定义类加载器
负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,这个加载器是由C++写的,所以我们在java源码里面是找不到它的实现,如果尝试对它进行打印,输出将为空值。
AI码师
2022/12/22
3860
从源码角度学习JVM类加载器及自定义类加载器
内存泄漏 - 从Class类加载器说起
某公司技术人员针对企业应用系统12月10日内存溢出事件进行了广泛的技术探讨,并得到了一些建设性的建议和结论。
IT技术小咖
2019/09/24
2.9K0
内存泄漏 - 从Class类加载器说起
详细讲解!从JVM直到类加载器
整个过程是,x.java文件需要编译成x.class文件,通过类加载器加载到内存中,然后通过解释器或者即时编译器进行解释和编译,最后交给执行引擎执行,执行引擎操作OS硬件。
java技术爱好者
2020/09/22
4320
JVM | 从类加载到JVM内存结构
我在上篇文章:JVM | 基于类加载的一次完全实践 中为你讲解如何请“建筑工人”来做一些定制化的工作。但是,大型的Java应用程序时,材料(类)何止数万,我们直接堆放在工地上(JVM)上吗?相反,JVM有着一套精密的管理机制,来确保类的加载、验证、解析和初始化等任务能够有序且高效地完成。
kfaino
2023/10/02
2750
JVM | 从类加载到JVM内存结构
在成为CTO之前,程序员怎样赚外快?
作为一个码code的程序员,虽然可能没有朋友,比较宅,但是整体花销往往不比正常人少。VPS,域名,MAC还有一堆的收费软件,数码设备等,都是卖肾的节奏。 当然作为程序员,我们也可以有更多的赚钱姿势,如果你认为只有接私单,那么你就OUT了,我们看看有没有其他的方式呢? 私单 最理想的单子还是直接接海外的项目,比如freelance.com等网站。一方面是因为挣的是美刀比较划算,之前看到像给WordPress写支付+发送注册码这种大家一个周末就能做完的项目,也可以到200~300美刀;另一方面是在国外接单子比较
春哥大魔王
2018/04/16
1.8K0
原 数据接收和数据返回呈现,都用一个类代替
import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; public class Record extends HashMap implements Map {     private static final lo
kinbug [进阶者]
2018/06/13
4500
Java类加载-加载
我们已经将整个Class的构成讲述完了,不清楚的同学可以看一下关于Class文件的介绍,但是空有Class并没有什么用,在Class中的各种描述信息都需要被加载到虚拟机以后才能运行使用。
shysh95
2021/02/25
1.3K0
Java类加载-加载
python 数据图表呈现
平时压力测试,生成一些数据后分析,直接看 log 不是很直观,前段时间看到公司同事分享了一个绘制图表python 模块 : plotly, 觉得很实用,利用周末时间熟悉下。
orientlu
2018/09/13
1.2K0
python 数据图表呈现
ajax请求完之前的loading加载
很多时候我们需要引入框架来开发项目,这时我们可能会遇到页面还没加载完源码出来了的问题,给用户一种不好的视觉体验,这是便需要loading加载了,来完善用户体验!
ProsperLee
2018/10/24
1.5K0
ajax请求完之前的loading加载
DevExpress数据绑定呈现
数据库这里为了方便演示,用的SQL Server 由于我数据库中的表有8列数据,这里添加8列,并设置列名和绑定的数据名称:
别团等shy哥发育
2023/02/27
1.6K0
DevExpress数据绑定呈现
类加载
其中类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的运行时绑定(也成为动态绑定或晚期绑定)。另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。
码农戏码
2021/03/23
4980
类加载
我们知道在运行Java程序时,首先需要把源代码编译成二进制文件也就是class文件,然后虚拟机才能执行。那虚拟机在执行class文件时,都进行了哪些步骤呢。下面我们将详细分享一下。当类也就是class文件被加载到虚拟机内存开始,到卸载出内存为止。它将要执行以下7个步骤:
吉林乌拉
2019/08/14
4970
类加载
启动类加载器,Bootstrap ClassLoader,加载JACA_HOME\lib,或者被-Xbootclasspath参数限定的类 扩展类加载器,Extension ClassLoader,加载\lib\ext,或者被java.ext.dirs系统变量指定的类 应用程序类加载器,Application ClassLoader,加载ClassPath中的类库 自定义类加载器,通过继承ClassLoader实现,一般是加载我们的自定义类
葆宁
2019/04/18
4850
类加载
【Android 逆向】类加载器 ClassLoader ( 启动类加载器 | 扩展类加载器 | 应用类加载器 | 类加载的双亲委托机制 )
类加载器加载类流程 : Bootstrap ClassLoader 先加载系统的核心类库 , Extention ClassLoader 加载额外的 /lib/ext 类库 , Application ClassLoader 加载开发者自己开发的类库 ;
韩曙亮
2023/03/30
8920
从ng1看ng2 关于NgModule的简易归纳
最近开始折腾ng2,其实说是ng2,到目前为止,它已经发布了4.3版,就是这么的高产,高产似*,我连2都还木有完整的看完它竟然发布了4.的版本(鄙视脸)。
littlelyon
2018/10/19
9550
写一个Foreach帮助类,在razor中使用
esterday, during my ASP.NET MVC 3 talk at Mix 11, I wrote a useful helper method demonstrating an advanced feature of Razor, Razor Templated Delegates.
javascript.shop
2019/09/04
4980
jvm怎么加载类_jvm类加载器
原因: 1、存放在自定义路径上的类,需要通过自定义类加载器去加载。【注意:AppClassLoader加载classpath下的类】 2、类不一定从文件中加载,也可能从网络中的流中加载,这就需要自定义加载器去实现加密解密。 3、可以定义类的实现机制,实现类的热部署, 如OSGi中的bundle模块就是通过实现自己的ClassLoader实现的, 如tomcat实现的自定义类加载模型。
全栈程序员站长
2022/10/29
4670

相似问题

Shell脚本在特定单词之后打印一定数量的单词

34

在shell脚本中从文件中选择特定的单词

20

在特定单词之后提取单词

30

在shell脚本中搜索特定的单词

34

PHP在某个单词之后选择单词

25
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档