web-dev-qa-db-ja.com

Kotlinコルーチンを使用したPublishSubject(フロー)

私はPublishSubjectを使用し、それにメッセージを送信し、結果をリッスンしていました。これは問題なく動作しましたが、今はKotlinのコルーチン(フローまたはチャネル)で同じことを行う方法がわかりません。

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
    }
}

なにが問題ですか?

10
mayyyo

Flow は、Obserableと同様に、コールド非同期ストリームです。

mapfilterなどのフローのすべての変換はフローの収集または実行をトリガーせず、ターミナルオペレーター(例:single)のみがトリガーします。

onEachメソッドは単なる変換です。したがって、これをターミナルフロー演算子collectに置き換える必要があります。また、BroadcastChannelを使用してよりクリーンなコードを作成することもできます。

private val channel = BroadcastChannel<Boolean>(1)

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

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

KotlinコルーチンのArrayBroadcastChannelは、PublishSubjectに最も類似したものです。

  1. PublishSubjectと同様に、ArrayBroadcastChannelは複数のサブスクライバーを持つことができ、アクティブなサブスクライバーすべてにすぐに通知されます。
  2. PublishSubjectと同様に、この時点でアクティブなサブスクライバーがない場合、このチャネルにプッシュされたイベントは失われます。

PublishSubjectとは異なり、バックプレッシャーはコルーチンチャネルに組み込まれており、そこにバッファー容量が入ります。この数は、チャネルが使用されているユースケースに実際に依存します。ほとんどの通常の使用例では、10以上で十分です。イベントをこのチャネルにプッシュするのが、それを消費するレシーバーよりも高速である場合は、より多くの容量を提供できます。

1
Nishanth