Grokai * RxJava、パート1:基本

*翻訳者から:「to grok」という動詞をロシア語に翻訳する方法について考えてきました。 一方で、この単語は「理解する」または「実現する」と翻訳され、他方では、ロバートハインラインの小説「異国での見知らぬ人」(この単語が最初に生まれた)を翻訳するとき、翻訳者はそれをロシア語にしたとどろきます。」 私は小説を読まなかったので、この単語にはロシア語の類似物によって伝えられなかった意味的なニュアンスがあると考えたため、英語の同じトレーシングペーパーを翻訳に使用しました。



RxJavaは、Androidプログラマーの間で議論する最もホットなトピックの1つになりました。 唯一の問題は、このような何かに出会っていない場合、その基本を理解することは非常に難しいことです。 関数型リアクティブプログラミングは、命令型の世界から来た場合には理解するのが非常に困難ですが、対処するやいなや、それがいかにクールであるかを実感できます!

RxJavaについての一般的なアイデアをお伝えします。 この一連の記事の目的は、すべてを最後のコンマまで説明することではなく(これを行うことはほとんどできませんでした)、むしろRxJavaとその仕組みに興味を持つことです。



基本



リアクティブコードの基本的な構成要素は、 Observables



Subscribers



1Observable



はデータソースであり、 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); //  "Hello, world!"
      
      





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); //  "Hello, world!"
      
      





それでは、チェーンメソッド呼び出しに頼って変数を削除しましょう。



 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よろしい、それほど無限ではありません。ある時点で鉄によって課せられた制限に我慢するからです。



All Articles