RxJava2を使用して同期および非同期APIをオブザーバブルに変換する
1. 概要
このチュートリアルでは、how to transform traditional synchronous and asynchronous APIs into Observables using RxJava2演算子について学習します。
これらの演算子について詳しく説明するのに役立ついくつかの簡単な関数を作成します。
2. Mavenの依存関係
まず、Mavenの依存関係としてRxJava2とRxJava2Extensionsを追加する必要があります。
io.reactivex.rxjava2
rxjava
2.2.2
com.github.akarnokd
rxjava2-extensions
0.20.4
3. オペレータ
RxJava2は、リアクティブプログラミングのさまざまなユースケースに対してa whole lot of operatorsを定義します。
ただし、同期メソッドまたは非同期メソッドをその性質に基づいてObservablesに変換するために一般的に使用されるいくつかの演算子についてのみ説明します。 These operators take functions as arguments and emit the value returned from that function。
RxJava2は、通常の演算子に加えて、拡張機能用の演算子をいくつか定義しています。
これらの演算子を使用して同期メソッドと非同期メソッドを変換する方法を見てみましょう。
4. 同期メソッド変換
4.1. fromCallable()の使用
この演算子はObservableを返します。これは、サブスクライバーがサブスクライブすると、引数として渡された関数を呼び出し、その関数から返された値を出力します。 整数を返す関数を作成して変換してみましょう。
AtomicInteger counter = new AtomicInteger();
Callable callable = () -> counter.incrementAndGet();
それでは、それをObservableに変換し、サブスクライブしてテストしてみましょう。
Observable source = Observable.fromCallable(callable);
for (int i = 1; i < 5; i++) {
source.test()
.awaitDone(5, TimeUnit.SECONDS)
.assertResult(i);
assertEquals(i, counter.get());
}
The fromCallable() operator executes the specified function lazily each time when the wrapped Observable gets subscribed.この動作をテストするために、ループを使用して複数のサブスクライバーを作成しました。
リアクティブストリームはデフォルトでは非同期であるため、サブスクライバーはすぐに戻ります。 実用的なシナリオのほとんどでは、呼び出し可能関数には、実行を完了するための何らかの遅延があります。 したがって、呼び出し可能な関数の結果をテストする前に、we’ve added a maximum wait time of five secondsを実行します。
Observableのtest()メソッドを使用したことにも注意してください。 This method is handy when testing Observables.TestObserver を作成し、Observable.にサブスクライブします
4.2. start()の使用
start()演算子は、RxJava2Extensionモジュールの一部です。 指定された関数を非同期で呼び出し、結果を出力するObservableを返します。
Observable source = AsyncObservable.start(callable);
for (int i = 1; i < 5; i++) {
source.test()
.awaitDone(5, TimeUnit.SECONDS)
.assertResult(1);
assertEquals(1, counter.get());
}
この関数は、サブスクライバーが結果のObservableをサブスクライブするたびにではなく、すぐに呼び出されます。 Multiple subscriptions to this observable observe the same return value.
5. 非同期メソッド変換
5.1. fromFuture()の使用
ご存知のように、Javaで非同期メソッドを作成する最も一般的な方法は、Future実装を使用することです。 fromFutureメソッドは、引数としてFutureを取り、Future.get()メソッドから取得した値を出力します。
まず、以前に作成した関数を非同期にします。
ExecutorService executor = Executors.newSingleThreadExecutor();
Future future = executor.submit(callable);
次に、変換してテストを行いましょう。
Observable source = Observable.fromFuture(future);
for (int i = 1; i < 5; i++) {
source.test()
.awaitDone(5, TimeUnit.SECONDS)
.assertResult(1);
assertEquals(1, counter.get());
}
executor.shutdown();
また、各サブスクリプションが同じ戻り値を監視していることにもう一度注意してください。
現在、Observableのdispose()メソッドは、メモリリークの防止に関して非常に役立ちます。 ただし、この場合、Future.get()のブロックの性質により、将来はキャンセルされません。
したがって、source observableのcombining the doOnDispose()関数とfutureのcancelメソッドによって、将来を確実にキャンセルできます。
source.doOnDispose(() -> future.cancel(true));
5.2. startFuture()の使用
名前が示すように、この演算子は指定されたFutureをすぐに開始し、サブスクライバーがサブスクライブすると戻り値を出力します。 次の使用のために結果をキャッシュするfromFuture演算子とは異なり、this operator will execute the asynchronous method each time when it gets subscribed:
ExecutorService executor = Executors.newSingleThreadExecutor();
Observable source = AsyncObservable.startFuture(() -> executor.submit(callable));
for (int i = 1; i < 5; i++) {
source.test()
.awaitDone(5, TimeUnit.SECONDS)
.assertResult(i);
assertEquals(i, counter.get());
}
executor.shutdown();
5.3. deferFuture()の使用
This operator aggregates multiple Observables returned from a Future method and returns a stream of return values obtained from each Observable.これにより、新しいサブスクライバーがサブスクライブするたびに、渡された非同期ファクトリ関数が開始されます。
それでは、最初に非同期ファクトリ関数を作成しましょう。
List list = Arrays.asList(new Integer[] { counter.incrementAndGet(),
counter.incrementAndGet(), counter.incrementAndGet() });
ExecutorService exec = Executors.newSingleThreadExecutor();
Callable> callable = () -> Observable.fromIterable(list);
そして、簡単なテストを行うことができます。
Observable source = AsyncObservable.deferFuture(() -> exec.submit(callable));
for (int i = 1; i < 4; i++) {
source.test()
.awaitDone(5, TimeUnit.SECONDS)
.assertResult(1,2,3);
}
exec.shutdown();
6. 結論
このチュートリアルでは、同期メソッドと非同期メソッドをRxJava2オブザーバブルに変換する方法を学習しました。
もちろん、ここで示した例は基本的な実装です。 しかし、ビデオストリーミングなどのより複雑なアプリケーションや、大量のデータを分割して送信する必要があるアプリケーションには、RxJava2を使用できます。
いつものように、ここで説明したすべての短い例は、Github projectにあります。