Androidアプリ開発 Rxjava2 時刻表示アプリを作成してFlowableを理解する

Androidアプリ開発でRxJava2を使うと、UIの実装が便利になります。
この記事は、AndroidアプリでRxJava2のFlowableの使い方を記載した記事です。
環境はAndroid 7.1 (API level 25) です。
環境
- OS X El Capitan
- android sdk 25
- Oracle jdk version 1.8.0_72
- Android Studio 2.2.3
- Rxjava 2.0.1
難易度
中級者向け
サンプルコード
Rxjava2
Rxjavaは、Javaでリアクティブプログラミングをするためのライブラリです。
リアクティブプログラミングは、送られてきたデータを受け取るたびに反応して処理をするプログラミングです。
Rxjavaはデータを作成して通知する生産者(Publisher)と、データを受け取り処理を行う消費者(Subscriber)で構成されています。
Rxjava2ではObservableとほぼ同じ機能を提供するFlowableクラスが新たに導入されました。両者の違いは、Backpressure機能の有無です。Backpressureについてはここで詳しく説明しています。
インストール
Rxjavaのインストールの設定をgradleにします。
Rxjavaのバージョンはbuild.gradleに次のように記述します。
ext { buildToolsVersion = "25.0.2" supportLibVersion = "25.1.1" rxandroidVersion = "2.0.1" rxjavaVersion = "2.0.1" rxjavaOptional = "1.1.0" threetenabp = "1.0.5" }
Rxjavaの情報は、app/build.gradleに次のように記述します。
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:' + rootProject.supportLibVersion compile 'com.android.support:design:' + rootProject.supportLibVersion compile 'com.android.support:support-v4:' + rootProject.supportLibVersion compile 'io.reactivex.rxjava2:rxandroid:' + rootProject.rxandroidVersion // Because RxAndroid releases are few and far between, it is recommended you also // explicitly depend on RxJava's latest version for bug fixes and new features. compile 'io.reactivex.rxjava2:rxjava:' + rootProject.rxjavaVersion // https://github.com/JakeWharton/ThreeTenABP compile 'com.jakewharton.threetenabp:threetenabp:' + rootProject.threetenabp testCompile 'junit:junit:4.12' }
ビルド後に、RxJava2の実装が可能になります。
アプリ設計
サンプルとして、以下のような時刻表示アプリを作成します。

Rxjava2のFlowableを使って現在の時間を表示するだけのシンプルなアプリです。
実装
画面のベースになるActivityを作成します。
クラス名はTimeDisplayActivityにします。
public class TimeDisplayActivity extends AppCompatActivity { private static final String TAG = "TimeDisplayActivity"; private TextView time; private Disposable disposable; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_time_display); AndroidThreeTen.init(this); time = (TextView) findViewById(R.id.timer); +// 生産者を作成(create Producer) disposable = Flowable.interval(1000L, TimeUnit.MILLISECONDS) // スレッド(thread) .observeOn(AndroidSchedulers.mainThread()) // 購読(subscribe) .subscribe(aLong -> { updateTimeView(); }); } /** * update TimeTextView * Timeのviewを更新する */ private void updateTimeView() { +LocalDateTime current = LocalDateTime.now(); StringBuffer str = new StringBuffer(); str.append(current.getHour() + " : " + current.getMinute() + " : " + current.getSecond()); time.setText(str.toString()); } @Override protected void onDestroy() { super.onDestroy(); if (disposable != null && !disposable.isDisposed()) { disposable.dispose(); } } }
■ 実装の解説
1. Flowable
Flowableは、Publisherを実装した生産者のクラスです。
Rxjava2から導入されたクラスで、Rxjava1から存在するObservableとほとんど同じ機能を提供します。
Observableとの違いは、Backpressureの機能が利用できることです。
Flowable
また、Flowableはcoldな生産者です。coldな生産者では、subscribeされるたびにデータを通知するストリームが作成されます。Rxjavaでは、基本的にcoldな生産者になります。
2. Backpressure
Backpressureは、データを通知する量をコントロールする機能です。Rxjava2では、FlowableだけがBackpressureの機能を持っています。Observableにはありません。
この機能は、データの通知スピードが受け取り側の処理より早い場合に利用します。通知スピードが受け取り側の処理より早い場合、受け取り側の処理が間に合わなくて、処理待ちのデータがたまってしまいます。これを解決するのがBackpressureです。
Rxjava2から、ObservableでBackpressureの機能が利用できなくなったことも認識しておきましょう。Backpressureの機能を利用していない場合は、FlowableとObservableの違いを気にする必要はありません。
3. interval
intervalメソッドは引数に指定した間隔で、Flowableオブジェクト(生産者)を発行します。
Flowable.interval(1000L, TimeUnit.MILLISECONDS)
4. observeOn
observeOnメソッドは、データを受け取った側(消費者)の処理を、どのようなSchedule上で行うのかを設定するメソッドです。
observeOn(AndroidSchedulers.mainThread())
observeOnメソッドが指定したSchedulerが設定したスレッド上で、それ以降の処理を行うようになります。
上記の処理は、データを受け取る側(消費者)が、AndroidのUIの場合に利用します。このサンプルでは、データを受け取るのがUIのTextViewなので、AndroidSchedulers.mainThread()を使います。このメソッドを呼びださないと、Only the original thread that created a view hierarchy can touch its viewsが発生します。
5. subscribe
Flowable(生産者)が通知したデータを、消費者が購読します。
.subscribe(aLong -> { updateTimeView(); });
このサンプルの購読する消費者はTextViewです。
Rxjava2では、ほぼ同じ機能であるsubscribeWithメソッドも使用できます。このサンプルコードでは不要なので、使用しません。
6. LocalDateTime
Java8から導入された日付クラスです。まだAndroidでは利用できないので、バックポートで取り入れています。
AndroidThreeTen.init(this); LocalDateTime current = LocalDateTime.now(); StringBuffer str = new StringBuffer(); str.append(current.getHour() + " : " + current.getMinute() + " : " + current.getSecond());
7. Disposable
購読を解除します。
if (disposable != null && !disposable.isDisposed()) { disposable.dispose(); }
isDisposed()メソッドで購読状態を判定してから、購読を解除します。
ビルド
上記のコードビルドして動作を確認します。

1秒間隔で更新される時刻が表示できました。
結論
RxJava2を使うと少ないコード量で通知と受信の実装が可能です。理解するまでが大変ですが、使ってみてください。