update.全てをストリームに感じろこんにちは。最近、RxとかRxJavaとかRxAndroidとかすごい流行ってますよね。流行に乗って私も勉強し始めたのですが、結構長い間理解できませんでした。(というか、今もできてません)いろんな記事とか読んでても、「つまりどういうことだってばよ」と意味がわからないことがとても多かったです。Observableってなに?Observerパターンと何が違うの?ストリームってなに?あのヘンテコな図読めないんだけど?非同期処理が得意なのはわかったけど、それだけ?それしかできないの?みたいなところがとてもつらかったです。読んでても、全てがストリームになる感覚が全然掴めなくて、途中に出てくるこの犬の気持ちがさっぱり分からなくてつらい思いをしたのをよく覚えています。そんなRx初心者な私が、全てがストリームになる感覚を一瞬感じられた瞬間があったので、そのためにやったことをまとめてみようと思います。RxAndroidを使ってAndroidアプリを作りますretrolambda使って処理を簡略化してますdatabindingステキRxの基本的な使い方とか、それぞれの機能の意味などは細かく説明しませんpackageやimport文は省略していますRxを使わないでカウントアプリを作ってみる今回作るのは、すごい簡単なアプリです。これを全てストリームに出来なくて、どうしてストリームを理解出来ようか。最終形はこんな感じ(数字が減るボタンも最終的には用意しましたが、まずは+ボタンだけ作っていきます)これをさくっと作ってみましょう。</RelativeLayout></layout>じゃあMainActivityの方の処理も書いていきましょう。countTextViewに表示するという感じです。}}たったこれだけですね。これを1つずつストリームにしてストリームを感じていきましょう。OnClickのイベントをストリームにまず、OnClickイベントをストリーム化しましょう。Rxにはいくつかの登場人物がいますが、端折って説明すると以下の3役がいます。onsubscribe(発行されるもの。ここが全ての始まり)observable(観測されるもの。これがストリームだ)subscriber(購読者。最終的に仕事する人)ストリームを感じるには、ストリームが始まらないと意味がありません。よって、onsubscribeをするものを作成していきます。onsubscribeonsubscribeというのは、端的にいうと「イベントの発行元」です。今回の場合、「OnClick」イベントをストリーム化していくので、「あるViewがClickされたらストリームを進める」onsubscribeを作っていきます。}}RxJavaでは、Observable.OnSubscribeと呼ばれるinterfaceを実装することでonsubscribeを作ることが出来ます。callメソッドの中で呼び出されている部分が、ストリームのスタート地点で、ストリームが作成されたときに呼び出されます。ストリームを進めるというコードが書かれています。渡している引数ですが、これはストリームに流す値を決めるところで、今回は使用しないので何でも良かったのですがとりあえず押されたViewを流しておきました。(補足)Androidのonsubscribeについてイベントをonsubscribe化する手順としては上で説明したとおりですが、こんなことを全てのイベントでいちいち作っていくのはとても大変ですよね。実は、RxBindingというライブラリを使えばそれらを自分で作らなくても良いのですが、今回は勉強のために一から作りました。https://github.com/JakeWharton/RxBinding実用するときには、このライブラリを導入してやっていきたいですね。observableでは、次はMainActivityの方を書き換えていきます。上で作ったonsubscribeを流すストリーム、observableを作成していきます。ストリームは流さないと意味がありません。}}observableを作成するときには、onsubscribeが必要です。ストリームを流す大元の存在から、ストリームが生み出されるのだから当然ですね。今回は、上で作成したViewClickOnSubscribeによって、plusButtonが押されたら値を流すストリームがこれで作成されました。subscriberそれでは、このストリームから値を受け取って処理をしましょう。今回の場合は、値を受け取ったら数字を1足してcountTextViewに表示するsubscriberを作成します。}}おや、subscriberはどこにいるんでしょうか?いえいえ、安心してください。subscriberは、lambda式となって私たちの前に現れています。上のコードの、plusButtonClickObservable.subscribeの中の部分がsubscriberです。lambda式になっていると少し分かりづらいですね。lambda式になる前のコードを見てみましょう。}});こんな感じです。分かりにくい?しょうがないなぁ。}});これならわかりますね。Subscriberの役割は、ストリームに流れてきた値を受け取って処理をすることです。「値を受け取る」部分には、今回はViewを流していましたね。onNextの引数の型はViewとなっています。先ほどは説明していませんでしたが、ストリームにはエラーと終了を流すこともできます。Subscriberはそれらの値を受け取って、上のように処理を分けて書くことができる、というわけです。今回の例では、エラーを流すことも終了を流すことも必要ないため、特に断りが無い限りは一番上の方法で書いていきます。(一番上の方法は、onNextだけを書くことが出来る)さて、これで当初の目的である、「OnClickのイベントをストリームに」が達成されました。この時点で一度実行してみてください。ボタンを押したら、数字が1増えて表示されるという挙動が何一つ変わらず実現されているはずです。このままじゃただOnClickListenerをストリームとかいう分かりにくいものに置き換えたに過ぎません。ムダにコードも増えてるし、これじゃやらないほうがマシだ!と言われても仕方ないでしょう。いうことで、Observableの利点を紹介しながらもっとストリームを感じていきましょう。ストリームをもっと感じよう先ほどまでのコードでは、ストリームに対してなにも処理を加えませんでした。流れ続けるストリーム、そんなものに私たちは興味がありません。ストリームの利点はいくつかありますが、大事なのはやっぱりこれでしょう。ストリームを別のストリームに変換することが出来る複数のストリームを1つにまとめることが出来る1つずつ説明しながらカウントアプリを強化していきます。ストリームを変換するこれはどういうことかというと、「ストリームに流れてくる値を別の形に書き換えることが出来る」ということです。Rxには、ストリームに流れてくる値に対して様々な変化を加えることが出来る強力な機能群が揃っています。今回のカウントアプリでは、countという変数を用意していました。これは、ストリームを変換することで不要となります。countTextView.setText(String.valueOf(n)));大分いきなり形が変わって驚いたかと思います。これも1つずつやっていきましょう。使うと、ストリームに流れてきた値を別の値に変換することが出来ます。これは一番単純で分かりやすいストリームの変換でしょう。今回は、ストリームに流れてくるViewを1という数字に変換しました。この変換作業によって、ストリームは新しいplusButtonNumberObservableというストリームに生まれ変わることになります。i);これもストリームの変換です。observable.scanは、ストリームに流れてきた値を、これまで流れてきた値全てと組み合わせることができます。いう記事の画像を見るとすごくよくわかります。http://qiita.com/disc99/items/1b2e44a1105008ec3ac9#scan「今までストリームに"流した値"と、今ストリームに"流れてきた値"を組み合わせて、ストリームに値を流す」ことができるということです。上のコードでは、accにはplusButtonNumberObservableに今まで流した値が、iにはplusButtonClickCountObservableに流れてきた値が入っています。これを足し合わせると、次にaccに流れる値がplusButtonClickCountObservableストリームに流れる、という形です。分かりづらいかもしれないので、表にしてまとめてみました。6これを見れば分かる通り、plusButtonNumberObservableのストリームにはボタンを押した数が入っていくことが見て取れますね。最終的に、これをsubscribeして数字を表示することで数字をカウントすることが出来ます。countTextView.setText(String.valueOf(n)));このように、ストリームを別のストリームに変換することが出来るのが大きな特徴です。カウントアプリの例じゃ分かりづらかったかもしれませんが、たとえばObserverパターンやPub/Subパターンなどでは、こういった「値の変換」は自由に行うことが出来ず、受け取る側でそれぞれ変換する必要があります。変換途中のストリームが独立して分けられるので、複数のsubscriberに対して途中のストリームを流すということもできます。した柔軟な対応が行えるのは、Rxの1つの大きな利点だと思います。通信処理などを書いていると、レスポンスで受け取った値を使ってさらにリクエストを送りたい、といったことをしたいときが多くあると思います。(俗にいう、callback地獄というやつです)ストリームの変換を行えば、受け取った値を別の通信ストリームに変換するなんて造作も無いことです。callback地獄が一点、ストリーム天国へと昇華します。複数のストリームを1つにまとめることが出来るRxのもう1つの大きな特徴として、複数のストリームを1つにまとめることができます。これが個人的には最大の利点だと思っていて、ストリームを感じるための大きなきっかけとなったものでした。カウントアプリにマイナスボタンを付けながら、複数のストリームをまとめてストリームを感じましょう。</RelativeLayout></layout>MainActivityをさくっと修正しましょう。}}plusボタンの方は上で説明したとおりですね。minusボタンの方も、plusボタンと同じようにストリームを作成しましょう。ここで重要な部分は、以下の部分です。minus);ここで、ストリームの合成を行っています。plusNumberObservableとminusNumberObservable、2つのストリームをかけ合わせて、新しいストリームを作ることが出来ます。今回は、Observable.combineLatestという機能で、2つのストリームのうちどちらかに値が流れてきたときに、両方のストリームに流れていた最新の値を取り出して、新しい値を流すストリームを作成することが出来ます。これも分かりづらいと思ったので、表にしました。1いかがでしょうか?plusボタンをクリックしたときにはminusNumberObservableには値は流れていませんが、combineLatestで作られたストリームにはplusNumberObservableとminusNumberObservableで流れた最新の値を足し合わせた値が流れます。あとは、このストリームでの値をcountTextViewに表示すれば、+ボタンとーボタンの実装が完成します。binding.countTextView.setText(String.valueOf(n));});この、「複数のストリームをかけ合わせて1つのストリームにする」のは、使いようによってはとても大きな効力を発揮します。「AというチェックボックスとBというフィールドに正しい値が入っていれば、Cというボタンが押せるようになる」という処理を書きたいときに、普通ならそれぞれのListenerに同じような処理をそれぞれ書く必要がありますが、ストリームにしてしまえばそれも簡単に実現できます。やるまた、非同期処理をしているときに、「Aの非同期処理とBの非同期処理がどっちも終わった後にCの処理をしたい」という要望は昔からとても多くあると思いますが、これもストリームにしてしまえば簡単に実現することが出来ます。いかがでしたか?カウントアプリを使って、ストリームを感じてみました。カウントアプリという単純な構造のアプリにRxを適用することは、ストリームを感じるのにとても有用だったと個人的に思っています。この犬のように悟りを開くまでにはまだたくさんの障壁がありますが、だいぶハードルが下がったと思います。これまで一切ストリームを感じれなかった人も、この記事を読んで少しでもストリームを感じることができたら幸いです。stream!!以上です。参考:Rxを勉強するときに読んだ記事たち全てをストリームに感じるまでに読んだ記事とか。分かりやすい記事ばかりでいつも助かっています。requestStockLike20@litmonとある恵比寿のAndroidエンジニアです。upLoginユーザーは見つかりませんでした。