Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何拆分一个';热的';来自Kotlin中回调的事件流?_Kotlin_Kotlin Coroutines_Kotlin Coroutines Flow - Fatal编程技术网

如何拆分一个';热的';来自Kotlin中回调的事件流?

如何拆分一个';热的';来自Kotlin中回调的事件流?,kotlin,kotlin-coroutines,kotlin-coroutines-flow,Kotlin,Kotlin Coroutines,Kotlin Coroutines Flow,我正在处理一系列事件,通过回调到达下游“我想把它分成多个流,并对它们进行处理。所有事件都是从一个线程按顺序到达的(我不控制它,所以我不认为我可以在这里使用协同例程) 这里使用的正确结构是什么 我可以使用callbackFlow和sendBlocking很容易地创建一个流,但是语义似乎不一致,因为流并不冷。 将流拆分为多个下游流的最佳方式是什么(取决于事件的内容)。还是应该使用频道?它与我的源代码的“热度”相匹配,但整个下游轮询似乎都关闭了(在这种基本上是同步的情况下),而且许多方法似乎不赞成使用

我正在处理一系列事件,通过回调到达下游“我想把它分成多个流,并对它们进行处理。所有事件都是从一个线程按顺序到达的(我不控制它,所以我不认为我可以在这里使用协同例程) 这里使用的正确结构是什么

我可以使用callbackFlow和sendBlocking很容易地创建一个流,但是语义似乎不一致,因为流并不冷。 将流拆分为多个下游流的最佳方式是什么(取决于事件的内容)。还是应该使用频道?它与我的源代码的“热度”相匹配,但整个下游轮询似乎都关闭了(在这种基本上是同步的情况下),而且许多方法似乎不赞成使用流

我可以通过使用“一路回调”来实现这一切,但这会产生比我希望的更紧密的耦合。有什么想法吗

编辑:

我的结局是这样的,似乎很有效:

fun testFlow(){
运行阻塞{
val原始=流量(“aap”、“noot”、“mies”、“wim”、“zus”、“jet”、“weide”、“does”)
val broadcast=original.broadcastIn(本)
val flow1=broadcast.openSubscription().receiveAsFlow().filter{it.length==4}
val flow2=broadcast.openSubscription().receiveAsFlow().filter{it.length==3}
flow1.collect{it->println(“四个字母:${it}”)}
flow2.collect{it->println(“三个字母:${it}”)}
}
}
简短回答 这个用例很快就会有一个热点,但在此期间,您可以在封面下使用
广播频道

您可以从创建基于回调的API的冷流开始(参见Roman Elizarov的)。 然后使用以下方法使其变热并共享:

val original: Flow<String> = TODO("get original flow")

// create an implicit hot BroadcastChannel, shared between collectors
val sharedFlow = original.broadcastIn(scope).asFlow()

// create derived cold flows, which will subscribe (on collect) to the
// same hot source (BroadcastChannel)
val flow1 = sharedFlow.filter { it.length == 4 }
val flow2 = sharedFlow.filter { it.length == 3 }.map { it.toUppercase() }

flow1.collect { it -> println("Four letter: ${it}") }
flow2.collect { it -> println("Three letter: ${it}") }
val-original:Flow=TODO(“获取原始流”)
//创建一个在收集器之间共享的隐式热广播频道
val sharedFlow=original.broadcastIn(作用域).asFlow()
//创建派生的冷流,该冷流将订阅(收集时)到
//同一热源(广播频道)
val flow1=sharedFlow.filter{it.length==4}
val flow2=sharedFlow.filter{it.length==3}.map{it.toUppercase()}
flow1.collect{it->println(“四个字母:${it}”)}
flow2.collect{it->println(“三个字母:${it}”)}
使流变热(当前方式) 首先要澄清的是,即使目前
Flow
s基本上是冷的,但是已经有一个热的
StateFlow
,并且很快就会有一个方便和热的方法来简化这种用例

在我们等待的过程中,如果您最初有一个冷
,那么您当前必须首先创建一个热通道(以及一个向其发送元素的协程),我们从中派生共享热源的流。这可以通过以下方式之一轻松完成:

  • 在给定范围内启动协同程序,并为您提供一个
    ReceiveChannel
    (用于扇出,请参见下文)
  • 在给定范围内启动协同程序,并为您提供
    广播频道
    (对实际共享有用,请参见下文)
一旦有了热通道,您就可以将其转换为流并获得不同的行为:

  • 从热源创建
    ,但它只能由单个收集器收集(否则抛出)
  • 创建多采集器
    ,但它以扇出方式运行(源通道中的每个元素仅流向一个使用者)
  • 创建一个多收集器
    ,其中每个收集器获取所有元素(有效共享)。调用
    collect
    BroadcastChannel
    上创建新订阅,并正确处理取消
带有
StateFlow的“最新状态”语义
这不是您的用例,但有时您可能不需要流中的所有值,而是最新的当前状态和状态更新

这过去是通过
合并的DBRoadCastChannel
完成的,但现在可以使用来表示这一点(自Corroutines 1.3.6以来):

  • 在producer端,设置
    MutableStateFlow
  • 在使用者端,每个采集器在启动时将获得当前状态,然后每次与前一个不同时(基于
    equal
    ity)都将获得新的状态值

我已经拼凑了一个例子,我觉得我很好,谢谢你。@FrankLee我刚才描述的和你现在做的有些相似。我只是使用
asFlow()
删除显式频道订阅,因为它会自动处理底层频道取消。请参阅我根据您的代码片段提供的示例代码。在这种情况下,使用
receiveAsFlow()
不会自动取消订阅频道,您应该选择
consumerasflow()
。也就是说,
openSubscription().consumeAsFlow()
会立即创建两个热流,而使用
asFlow()
实际上会使“子流”保持冷状态,并且只在订阅被收集时创建订阅。