今回の話
実装
【1.概要編】で書いた通りにストリームを利用してプログラミングをしていきたい場合、以下の3つの手順があると思っています。
1. ストリームを生成する
2. データソースを設定する
3. ストリームを操作する
この3つの手順を実現するために様々な方法があることが学習コストを引き上げる要因な気がしますので、一つ一つ解説していきます。
(参考:RxJava javadoc)
http://reactivex.io/RxJava/2.x/javadoc/
1.ストリームを生成する
多分以下の5種類があります。
クラス名 | 概要 |
---|---|
Observable | ストリーム生成の基本。基本的にはこのクラスを利用してストリームを生成する |
Single | Observableと同様にストリームを生成できる。ただし、以下の点が異なる 1.単一のインスタンスしか渡せない 2.一度イベントが発生した後は購読しない 絶対に一回しかデータが来ない(APIレスポンスを流すだけとか)というときはこちらを使うイメージ。 |
Maybe | ほぼほぼSingleと同じ。ただし"データを流さず終了"という選択ができる |
Completable | 値を返さないストリーム。処理はしたい別に画面表示しないし...というときに使うイメージ。 |
Flowable | 値の流入を制限できるストリーム。すっごい数のデータが来る可能性があればこちらを使うイメージ。 |
例えばSingleを使うと、一回しかデータが流れてこないことが確実なので「次またデータが流れてきた場合」のことを考えずに済みます。
そのため場合によってストリーム生成するクラスを書き分けた方が良いとは思うのですが、要するに基本的にはObservableで全て実現できるので、まず書き始めるときはObservable一択でよいと思っています。
2.データソースを設定する
データソースというのはストリームに流れるデータの元です。
後述しますが、createというAPIを使って以下のようにデータソースを設定してみます。
val stream = Observable.create<SensorEvent> { subscriber ->
val obj = object : SensorEventListener {
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
}
// 端末のセンサーが変更されたときに呼ばれるイベント
override fun onSensorChanged(event: SensorEvent?) {
if (event != null) subscriber.onNext(event)
}
}
sensorManager.registerListener(obj, sensor, SensorManager.SENSOR_DELAY_NORMAL)
}!!
このデータソースは"Android端末のセンサーイベント"になります。データソース上は端末のセンサーが反応すればデータが発生していますが、それはまだストリーム上に流れていません。データソース上からストリームにデータを流すには以下の処理が必要です。
subscriber.onNext(event)
ちなみに、もうデータを流したくないよ!というときは以下の記載をします。
subscriber.onComplete()
エラーが発生したよ!というときのフローも用意されています。以下のように記載します。
subscriber.onError()
上記のようにストリームに流すデータの大元の設定が必要です。
代表的なものを以下に記載します。
API名 | 概要 |
---|---|
just | 単一のデータ一つを流す。 |
fromArray | 配列のデータを流す。 |
create | どんなデータを流すか自由に書ける。 |
3. ストリームを操作する
データソースを設定してストリームにデータが流れてきました。この状態のストリームに対して様々な操作を行うことができます。
map
代表的なmap APIについて記載します。公式のJavaDocには以下のような図で表されています。
参照:https://raw.github.com/wiki/ReactiveX/RxJava/images/rx-operators/map.png例えばストリームにStringデータが流れてきたときにそれをIntデータが流れるストリームにしたい場合は以下のように記載します。
Observable.just("1").map{ item -> item.toInt() }
上記図の通り、ストリームに対してmapAPIを通じて新しくIntが流れるストリームが生成されるようなイメージです。
このようにストリームを操作していくことでほしいデータが流れるようにしていくことができます。
flatmap
RxJavaには非常に多くのAPIが用意されているので様々な操作が可能ですが、
基本的にflatmapだけ覚えておけば何でも書ける気がします。
今のストリームから全く別のストリームを作れる、というのがflatmapだと思ってます。
例えば以下のようにStringデータ一つに対してArrayを返すこともできます。
Observable.just("1")
.flatMap{item -> Observable.fromArray(arrayOf(item.toInt(), item.toInt() + 1 ))}
流れてきたデータを元にAPIを実行してレスポンス情報が流れるストリームを作ることもできますし、割と万能感がありますので最初はこちらを使って書いていきつつ、より綺麗にかけるAPIを探して行くのがいいのではないかと思います。
代表的なものを以下に記載します。
API名 | 概要 |
---|---|
map | 流れているデータを1:1で変換したストリームを生成する |
flatmap | 流れているデータを元に何かしらに変換したストリームを生成する |
filter | 条件に合うデータだけ流れるストリームを生成する |
次の話
【3.実践編】に続く。