*翻訳者から:「to grok」という動詞をロシア語に翻訳する方法について考えてきました。 一方で、この単語は「理解する」または「実現する」と翻訳され、他方では、ロバートハインラインの小説「異国での見知らぬ人」(この単語が最初に生まれた)を翻訳するとき、翻訳者はそれをロシア語にしたとどろきます。」 私は小説を読まなかったので、この単語にはロシア語の類似物によって伝えられなかった意味的なニュアンスがあると考えたため、英語の同じトレーシングペーパーを翻訳に使用しました。RxJavaは、Androidプログラマーの間で議論する最もホットなトピックの1つになりました。 唯一の問題は、このような何かに出会っていない場合、その基本を理解することは非常に難しいことです。 関数型リアクティブプログラミングは、命令型の世界から来た場合には理解するのが非常に困難ですが、対処するやいなや、それがいかにクールであるかを実感できます!
RxJavaについての一般的なアイデアをお伝えします。 この一連の記事の目的は、すべてを最後のコンマまで説明することではなく(これを行うことはほとんどできませんでした)、むしろRxJavaとその仕組みに興味を持つことです。
基本
リアクティブコードの基本的な構成要素は、 
Observablesと
Subscribers 1 。 
Observableはデータソースであり、 
Subscriberはコンシューマです。
Observableを介したデータ生成は、常に同じ手順に従って行われます
Observableは、一定量のデータを「放出」し( 
Observableは何も出力しない場合があります)、正常にまたはエラーで作業を完了します。 
Observableに
Subscriberライブしている各
Subscriberについて、 
Subscriber.onNext()メソッドが各データストリーム要素に対して呼び出され、その後
Subscriber.onComplete()と
Subscriber.onError()両方を呼び出すことができます。
これはすべて、通常の
「オブザーバー」パターンと非常に似ていますが、1つの重要な違いがあります。 
Observablesは、誰かが明示的にサブスクライブするまでデータの生成を開始しないことが多い
2 言い換えると、木が倒れても近くに誰もいない場合、倒れた音は
聞こえません 。
こんにちは世界!
小さな例を取り上げましょう。 最初に、単純な
Observable作成します。
 Observable<String> myObservable = Observable.create( new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> sub) { sub.onNext("Hello, world!"); sub.onCompleted(); } } ); 
Observableは文字列「Hello、world!」を生成して終了します。 次に、データを受信してそれを使用するために
Subscriberを作成します。
 Subscriber<String> mySubscriber = new Subscriber<String>() { @Override public void onNext(String s) { System.out.println(s); } @Override public void onCompleted() { } @Override public void onError(Throwable e) { } }; 
Subscriberは、 
Observableから渡された行を出力するだけです。 
myObservableと
mySubscriberができた
mySubscriber 、 
subscribe()メソッドを使用してそれらをリンクできます。
 myObservable.subscribe(mySubscriber);  
mySubscriberを
myObservableにサブスク
mySubscriberすると
myObservable 、 
myObservableは
mySubscriber onNext()および
onComplete()メソッドを
mySubscriber 、その結果、 
mySubscriberは「Hello、world!」をコンソールに出力し、実行を終了します。
コードを簡素化する
一般的に言って、「Hello、world!」をコンソールに出力するような単純なタスクには、あまりにも多くのコードを記述しました。 何が何であるかを簡単に理解できるように、このコードを特別に作成しました。 RxJavaには、この問題を解決するためのより多くの合理化された方法があります。
まず、 
Observable単純化しましょう。 RxJavaには、最も一般的なタスクの解決に適した
Observableを作成するためのメソッドがあります。 この例では、 
Observable.just()は1つのデータ要素を生成し、最初のオプション
3と同様に実行を完了します。
 Observable<String> myObservable = Observable.just("Hello, world!"); 
次に、 
Subscriber単純化します。 
onCompleted()および
onError()メソッドには関心がないため、別の基本クラスを使用して、 
onNext()で
onNext()する必要があるものを決定できます。
 Action1<String> onNextAction = new Action1<String>() { @Override public void call(String s) { System.out.println(s); } }; 
Actionは、 
Subscriber任意の部分を置き換えるために使用できます
onNext() 、 
onNext() 、 
onError() 、および
onCompete()代わりに実行される1つ、2つ、または3つの
Actionパラメーターを受け入れることができます。 つまり、 
Subscriberように置き換えることができます。
 myObservable.subscribe(onNextAction, onErrorAction, onCompleteAction); 
ただし、 
onError()および
onCompete()は必要ないため、コードをさらに簡素化できます。
 myObservable.subscribe(onNextAction);  
それでは、チェーンメソッド呼び出しに頼って変数を削除しましょう。
 Observable.just("Hello, world!") .subscribe(new Action1<String>() { @Override public void call(String s) { System.out.println(s); } }); 
最後に、Java 8のラムダを使用して、コードをさらに簡素化できます。
 Observable.just("Hello, world!") .subscribe(s -> System.out.println(s)); 
Androidで記述している(したがってJava 8を使用できない)場合は、 
retrolambdaを
強くお勧めし
ます 。これは、一部の場所で非常に冗長なコードを簡素化するのに役立ちます。
変換
新しいことを試してみましょう。
たとえば、コンソールに表示される「Hello、world!」に署名を追加します。 どうやってやるの? まず、 
Observableを変更できます。
 Observable.just("Hello, world! -Dan") .subscribe(s -> System.out.println(s)); 
これは、 
Observableが定義されているソースコードにアクセスできる場合に機能する
Observableがありますが、たとえば、誰かのライブラリを使用する場合など、常にそうなるとは限りません。 別の問題: 
Observableを多くの場所で使用しているが、 
場合によってのみ署名を追加したい
場合はどうでしょうか?
Subscriber書き換えを試すことができます。
 Observable.just("Hello, world!") .subscribe(s -> System.out.println(s + " -Dan")); 
このオプションも不適切ですが、他の理由によります。メインスレッドで実行できるため、サブスクライバをできるだけ軽量にしたいのです。 より概念的なレベルでは、サブスクライバーは、受信したデータを
変更するのではなく、 
応答する必要
があります。
中間段階で「Hello、world!」を変更できたら素晴らしいと思います。
オペレーターの紹介
そして、データ変換を目的としたこのような中間ステップがあります。 その名前は演算子であり、 
Observableと
Subscriber間でデータ操作に使用できます。 RxJavaには多くの演算子があります。そのため、最初は少数の演算子のみに焦点を当てる方が良いでしょう。
特定の状況では、 
map()演算子が最適です。これにより、1つのデータ要素を別のデータ要素に変換できます。
 Observable.just("Hello, world!") .map(new Func1<String, String>() { @Override public String call(String s) { return s + " -Dan"; } }) .subscribe(s -> System.out.println(s)); 
そして再び、ラムダに頼ることができます:
 Observable.just("Hello, world!") .map(s -> s + " -Dan") .subscribe(s -> System.out.println(s)); 
かっこいい? 大まかに言えば、 
map()演算子は
Observableであり、データの要素を変換します。 
Subscriberタスクを容易にするために、データに最も便利でシンプルな形式を与えるために必要と考えられる数の
map()チェーンを作成できます。
地図についてもう1つ()
map()の興味深い特性は、元の
Observableと同じ型のデータを生成する必要がないことです。
Subscriberが生成されたテキストではなく、そのハッシュを表示する必要があるとしましょう:
 Observable.just("Hello, world!") .map(new Func1<String, Integer>() { @Override public Integer call(String s) { return s.hashCode(); } }) .subscribe(i -> System.out.println(Integer.toString(i))); 
おもしろい:行から始めて、 
Subscriberは整数を受け入れます。 ところで、ラムダについては忘れていました。
 Observable.just("Hello, world!") .map(s -> s.hashCode()) .subscribe(i -> System.out.println(Integer.toString(i))); 
先ほど言ったように、 
Subscriberできる限り少ない作業
Subscriberしてもらいたいので、別の
map()を使用してハッシュを
String戻します:
 Observable.just("Hello, world!") .map(s -> s.hashCode()) .map(i -> Integer.toString(i)) .subscribe(s -> System.out.println(s)); 
これを見てください
Observableと
Subscriberは最初と同じように見えます! データを変換する中間ステップをいくつか追加しました。 生成された行に署名を追加するコードを再度追加することもできます。
 Observable.just("Hello, world!") .map(s -> s + " -Dan") .map(s -> s.hashCode()) .map(i -> Integer.toString(i)) .subscribe(s -> System.out.println(s)); 
それでは、次は何ですか?
「よく、いつものように、彼らは簡単な例を示しており、2行のコードでこの問題を解決できるので、この技術はクールだと言っています。」 同意する、例は本当に簡単です。 しかし、そこからいくつかの有用なアイデアを引き出すことができます。
アイデア#1: ObservableでSubscriberは何でもできる
あなたの想像力を制限しないでください
、あなたが望むものは何でも可能です。
Observableはデータベースクエリであり、 
Subscriberはクエリ結果を画面に表示する場合があります。 
Observableは、画面をクリックすることでもあります。 
Subscriberは、このクリックに対する反応を含む場合があります。 
Observableはネットワークから受信したバイトストリームであり、 
Subscriberはこのデータをストレージデバイスに書き込むことができます。
これは、ほとんどすべての問題を処理できる汎用フレームワークです。
アイデア#2: ObservableとSubscriberは、中間の中間ステップから独立しています
Observableとそれを
Subscriberライブしている
Subscriber間に、必要
Observableだけ
map()呼び出しを挿入できます。 システムは簡単に
構成でき、その助けを借りて、データの流れを非常に簡単に制御できます。 演算子が正しい入力/出力データで動作する場合、無限の長さ
4の変換のチェーンを書くことができます。
これらの重要なアイデアを一緒に見てみると、大きな可能性のあるシステムが表示されます。 ただし、現在は
map()演算子が1つしかないため、あまり記述しません。 この記事の第2部では、RxJavaを使用するときにすぐに使用できる多数の演算子について検討します。
2番目の部分に移動します。
1 Subscriberは
Observerインターフェイスを実装するため、後者を「基本的なビルディングブロック」と呼ぶことができますが、 
Subscriber.unsubscribe()などの便利なメソッドがいくつか追加されているため、実際にはほとんどの場合
Subscriber使用します。
2 RxJavaには「ホット」および「コールド」 
Observablesます。 ホット
Observableは、誰もサブスクライブしていない場合でも、継続的にデータを生成します。 したがって、コールド
Observableは、少なくとも1人のサブスクライバーがいる場合にのみデータを生成します(記事ではcold 
Observables使用しています)。 RxJavaの学習の初期段階では、この違いはそれほど重要ではありません。
3厳密に言えば、 
Observable.just()元のコードの完全な類似物で
Observable.just()ませんが、これが
なぜそうなるの
かについては記事の第3部でのみ説明します。
4よろしい、それほど無限ではありません。ある時点で鉄によって課せられた制限に我慢するからです。