消耗性通道

时间:2018-06-08 21:26:01

标签: kotlin kotlinx.coroutines

用例

T消耗ReceiveChannel<T>项的Android片段。消费后,T应从ReceiveChannel<T>删除。

我需要一个支持从中消耗物品的ReceiveChannel<T>。它应该作为FIFO队列。

我目前从我的用户界面附加到频道,如:

launch(uiJob) { channel.consumeEach{ /** ... */ } }

我通过致电uiJob.cancel()分离。

期望的行为:

val channel = Channel<Int>(UNLIMITED)

channel.send(1)
channel.send(2)
// ui attaches, receives `1` and `2`
channel.send(3) // ui immediately receives `3`
// ui detaches
channel.send(4)
channel.send(5)
// ui attaches, receiving `4` and `5`

不幸的是,当我从频道分离时,频道已关闭。这会导致.send(4).send(5)抛出异常,因为频道已关闭。我希望能够从频道中分离并使其保持可用状态。我怎么能这样做?

Channel<Int>(UNLIMITED)适合我的用例完美,除了,它会在取消订阅时关闭频道。我希望频道保持开放状态。这可能吗?

2 个答案:

答案 0 :(得分:1)

Channel.consumeEach方法调用Channel.consume方法,该方法在文档中包含以下内容:

  

通过在执行块后始终调用cancel,确保给定的块消耗给定通道中的所有元素。

因此解决方案是不使用consume[Each]。例如,你可以这样做:

launch(uiJob) { for (it in channel) { /** ... */ } }

答案 1 :(得分:1)

您可以使用BroadcastChannel。但是,您需要指定有限的尺寸(例如1),UNLIMITED0 BroadcastChannel(对于rendez-vous)ConflatedBroadcastChannel不支持。

您还可以使用LiveData,它始终为新订阅者提供最新价值,例如Fragment正在执行的操作。

顺便说一下,如果你的新ConflatedBroadcastChannel实例只收到最新值,这是一个大问题吗?如果没有,那么就去BroacastChannel。否则,"Time", "Container 1", "Container 1 pressure", "Container 2", "Container 2 pressure", and so on. s都不适合您的用例(尝试一下,看看您是否得到了您正在寻找的行为)。