RxJava 2 –フローラブル
1. 前書き
RxJava is a Reactive Extensions Java implementation that allows us to write event-driven, and asynchronous applications. RxJavaの使用方法の詳細については、intro article hereを参照してください。
RxJava 2はゼロから書き直され、複数の新機能が追加されました。その一部は、以前のバージョンのフレームワークに存在していた問題への対応として作成されました。
そのような機能の1つは、io.reactivex.Flowableです。
2. Observable vs. Flowable
以前のバージョンのRxJavaでは、バックプレッシャ対応ソースと非バックプレッシャ対応ソースを処理するための基本クラスは1つしかありませんでした–Observable.
RxJava 2では、これら2種類のソースの明確な区別が導入されました–背圧対応ソースは、専用クラスを使用して表されるようになりました–Flowable.
Observableソースはバックプレッシャをサポートしていません。 そのため、単に消費して影響を与えることができないソースに使用する必要があります。
また、多数の要素を処理している場合、Observableのタイプに応じて、backpressureに関連する2つのシナリオが発生する可能性があります。
いわゆる“coldObservable“,を使用する場合、イベントは遅延して発行されるため、オブザーバーがオーバーフローすることはありません。
ただし、“hotObservable”を使用すると、消費者が追いつけなくても、イベントが発生し続けます。
3. Flowableの作成
Flowableを作成するにはさまざまな方法があります。 私たちにとって便利なことに、これらのメソッドは、RxJavaの最初のバージョンのObservableのメソッドに似ています。
3.1. 単純なFlowable
Observable :の場合と同様に、just()メソッドを使用してFlowableを作成できます。
Flowable integerFlowable = Flowable.just(1, 2, 3, 4);
just()の使用は非常に簡単ですが、静的データからFlowableを作成することはあまり一般的ではなく、テスト目的で使用されます。
3.2. ObservableからFlowable
When we have an Observable we can easily transform it to Flowable using the toFlowable() method:
Observable integerObservable = Observable.just(1, 2, 3);
Flowable integerFlowable = integerObservable
.toFlowable(BackpressureStrategy.BUFFER);
変換を実行できるようにするには、ObservableをBackpressureStrategy.で強化する必要があることに注意してください。次のセクションで利用可能な戦略について説明します。
3.3. FlowableOnSubscribeからFlowable
RxJava 2では、機能インターフェイスFlowableOnSubscribeが導入されました。これは、コンシューマーがサブスクライブした後にイベントの発行を開始するFlowableを表します。
そのため、すべてのクライアントが同じイベントセットを受信し、FlowableOnSubscribeがバックプレッシャセーフになります。
FlowableOnSubscribeがあれば、それを使用してFlowableを作成できます。
FlowableOnSubscribe flowableOnSubscribe
= flowable -> flowable.onNext(1);
Flowable integerFlowable = Flowable
.create(flowableOnSubscribe, BackpressureStrategy.BUFFER);
ドキュメントには、Flowable.を作成するためのさらに多くの方法が記載されています
4. FlowableBackpressureStrategy
toFlowable()やcreate()のようないくつかのメソッドは、引数としてBackpressureStrategyを取ります。
BackpressureStrategyは列挙型であり、適用する背圧動作を定義します。 流動性。
イベントをキャッシュまたはドロップすることも、まったく動作を実装しないこともできます。最後のケースでは、バックプレッシャー演算子を使用してイベントを定義する必要があります。
BackpressureStrategyは、以前のバージョンのRxJavaに存在するBackpressureModeに似ています。
RxJava 2には5つの異なる戦略があります。
4.1. バッファ
If we use the BackpressureStrategy.BUFFER, the source will buffer all the events until the subscriber can consume them:
public void thenAllValuesAreBufferedAndReceived() {
List testList = IntStream.range(0, 100000)
.boxed()
.collect(Collectors.toList());
Observable observable = Observable.fromIterable(testList);
TestSubscriber testSubscriber = observable
.toFlowable(BackpressureStrategy.BUFFER)
.observeOn(Schedulers.computation()).test();
testSubscriber.awaitTerminalEvent();
List receivedInts = testSubscriber.getEvents()
.get(0)
.stream()
.mapToInt(object -> (int) object)
.boxed()
.collect(Collectors.toList());
assertEquals(testList, receivedInts);
}
これは、Flowable,でonBackpressureBuffer()メソッドを呼び出すのと似ていますが、バッファサイズまたはonOverflowアクションを明示的に定義することはできません。
4.2. Drop
BackpressureStrategy.DROPを使用して、消費できないイベントをバッファリングする代わりに破棄できます。
繰り返しますが、これはFlowableでonBackpressureDrop()を使用するのと似ています。
public void whenDropStrategyUsed_thenOnBackpressureDropped() {
Observable observable = Observable.fromIterable(testList);
TestSubscriber testSubscriber = observable
.toFlowable(BackpressureStrategy.DROP)
.observeOn(Schedulers.computation())
.test();
testSubscriber.awaitTerminalEvent();
List receivedInts = testSubscriber.getEvents()
.get(0)
.stream()
.mapToInt(object -> (int) object)
.boxed()
.collect(Collectors.toList());
assertThat(receivedInts.size() < testList.size());
assertThat(!receivedInts.contains(100000));
}
4.3. 最新
BackpressureStrategy.LATESTを使用すると、ソースは最新のイベントのみを保持するように強制されるため、コンシューマーが追いつけない場合は、以前の値が上書きされます。
public void whenLatestStrategyUsed_thenTheLastElementReceived() {
Observable observable = Observable.fromIterable(testList);
TestSubscriber testSubscriber = observable
.toFlowable(BackpressureStrategy.LATEST)
.observeOn(Schedulers.computation())
.test();
testSubscriber.awaitTerminalEvent();
List receivedInts = testSubscriber.getEvents()
.get(0)
.stream()
.mapToInt(object -> (int) object)
.boxed()
.collect(Collectors.toList());
assertThat(receivedInts.size() < testList.size());
assertThat(receivedInts.contains(100000));
}
コードを見ると、BackpressureStrategy.LATEST and BackpressureStrategy.DROPは非常によく似ています。
ただし、BackpressureStrategy.LATESTは、サブスクライバーが処理できない要素を上書きし、最新の要素のみを保持するため、この名前が付けられます。
一方、BackpressureStrategy.DROP,は、処理できない要素を破棄します。 これは、最新の要素が必ずしも放出されるとは限らないことを意味します。
4.4. エラー
BackpressureStrategy.ERROR,を使用しているときは、単にwe don’t expect backpressure to occurと言っています。 したがって、コンシューマーがソースについていけない場合は、MissingBackpressureExceptionをスローする必要があります。
public void whenErrorStrategyUsed_thenExceptionIsThrown() {
Observable observable = Observable.range(1, 100000);
TestSubscriber subscriber = observable
.toFlowable(BackpressureStrategy.ERROR)
.observeOn(Schedulers.computation())
.test();
subscriber.awaitTerminalEvent();
subscriber.assertError(MissingBackpressureException.class);
}
4.5. 行方不明
BackpressureStrategy.MISSINGを使用する場合、ソースは破棄またはバッファリングせずに要素をプッシュします。
この場合、ダウンストリームはオーバーフローに対処する必要があります。
public void whenMissingStrategyUsed_thenException() {
Observable observable = Observable.range(1, 100000);
TestSubscriber subscriber = observable
.toFlowable(BackpressureStrategy.MISSING)
.observeOn(Schedulers.computation())
.test();
subscriber.awaitTerminalEvent();
subscriber.assertError(MissingBackpressureException.class);
}
テストでは、ERRORとMISSINGの両方の戦略でMissingbackpressureExceptionを除外しています。 ソースの内部バッファがオーバーフローすると、両方ともそのような例外をスローするためです。
ただし、どちらも目的が異なることに注意してください。
背圧がまったく予想されない場合は前者を使用する必要があり、発生した場合に備えてソースが例外をスローするようにします。
後者は、Flowableの作成時にデフォルトの動作を指定したくない場合に使用できます。 そして、後でそれを定義するために背圧演算子を使用します。
5. 概要
このチュートリアルでは、RxJava2で導入されたFlowable.という新しいクラスを紹介しました。
Flowable自体とそのAPIの詳細については、documentationを参照してください。
いつものように、すべてのコードサンプルはover on GitHubで見つけることができます。