发布主题与Kotlin协程(流程)

时间:2019-05-13 11:22:16

标签: android kotlin rx-java kotlin-coroutines

我正在尝试将RX的一部分代码重构为协程,但是尽管我付出了所有努力,但我还是觉得迷路了。

所以我创建了PublishSubject,我正在向它发送消息,而且我也在听结果。它可以完美地工作,但是现在我不确定如何对协程(流或通道)执行相同的操作。

private val subject = PublishProcessor.create<Boolean>>()

...

fun someMethod(b: Boolean) {
    subject.onNext(b)
}

fun observe() {
    subject.debounce(500, TimeUnit.MILLISECONDS)
           .subscribe {
         // value received
    }
}

因为我需要使用反跳运算符,所以我真的想对流执行相同的操作,因此我创建了通道,然后尝试从该通道创建流并听取更改,但没有得到任何结果。

private val channel = Channel<Boolean>()

...

fun someMethod(b: Boolean) {
    channel.send(b)
}

fun observe() {
    flow {
         channel.consumeEach { value ->
            emit(value)
         }
    }.debounce(500, TimeUnit.MILLISECONDS)
    .onEach {
        // value received
    }
}

我怎么了?

4 个答案:

答案 0 :(得分:1)

Flow是一个冷的异步流,就像Obserable一样。

  

流上的所有转换(例如mapfilter都不会触发流的收集或执行,只有终端操作员(例如single)会触发流。

onEach方法只是一个转换。因此,您应该使用终端流量运算符collect代替它。另外,您可以使用BroadcastChannel来获得更简洁的代码:

private val channel = BroadcastChannel<Boolean>(1)

fun someMethod(b: Boolean) {
    channel.send(b)
}

fun observe() {
  channel
    .asFlow()
    .debounce(500, TimeUnit.MILLISECONDS)
    .collect {
        // value received
    }
}

答案 1 :(得分:1)

对于 PublishProcessor/PublishRelay 应该是 SharedFlow/MutableSharedFlow,对于 BehaviorProcessor/BehaviorRelay 应该是 StateFlow/MutableStateFlow

// initial value to constructor
private val _myFlow = MutableStateFlow<Boolean>("")
// expose as Flow<Boolean>
val myFlow = _myFlow 
...

fun someMethod(b: Boolean) {
    _myFlow.value = b
}

// this must be either `suspend` fun or create coroutine (`.launch{}`) inside to be able to `.collect`
suspend fun observe() {
    myFlow.debounce(500)
          .collect {  }
}

MutableStateFlow 在设置新值时使用 .equals 比较,因此它不会一次又一次地发出相同的值(相对于使用引用比较的 distinctUntilChanged

编辑我不确定 _myFlow.value=b_myFlow.emit(b) 的区别。有人开导

答案 2 :(得分:0)

Kotlin协程中的ArrayBroadcastChannel与PublishSubject最相似。

  1. 像PublishSubject一样,ArrayBroadcastChannel可以有多个 订户和所有活动订户将立即得到通知。
  2. 就像PublishSubject一样,如果当前没有活动的订阅者,则推送到此频道的事件也会丢失。

与PublishSubject不同,反压是内置在协程通道中的,这就是缓冲容量的来源。此数字实际上取决于通道用于的用例。对于大多数正常用例,我只用了10个,应该绰绰有余。如果您将事件推送到此频道的速度比接收者消费事件的速度快,则可以提供更多的容量。

答案 3 :(得分:0)

实际上 BroadcastChannel 已经过时了,Jetbrains 改变了他们的方法,改为使用 SharedFlows。哪个更干净、更容易实现并解决了很多痛点。

本质上,您可以像这样实现相同的目标。

class BroadcastEventBus {
    private val _events = MutableSharedFlow<Event>()
    val events = _events.asSharedFlow() // read-only public view

    suspend fun postEvent(event: Event) {
        _events.emit(event) // suspends until subscribers receive it
    }
}

要了解更多信息,请查看 Roman 的 Medium 文章。

"Shared flows, broadcast channels" by Roman Elizarov