Androidアプリ開発 RxJava AndroidアプリでRxJavaのObservableを使う

Androidアプリ開発でRxJavaを使うと、AndroidでもJava8的な文法を利用できます。さらには、API等を使った非同期処理を少ないコード量で記述することができます。
この記事は、AndroidアプリでRxJavaの基本的な使い方を記載した記事です。
環境はAndroid 7.0 (API level 24) です。
環境
- OS X Yosemite
- Oracle jdk version 1.8.0_72
- Android Studio 2.1.3
- android sdk 24
- rxandroid:1.2.1
- rxjava:1.1.6
難易度
中級者向け
サンプルコード
RxJava
RxJavaとはリアクティブプログラミングをおこなうライブラリであるReactive ExtensionsのJava VM実装です。
Observable
Observableは、Observableへsubscribingするためのメソッドを提供します。
乱暴に言うと、Observableは監視対象のデータを設定し、そのデータの流れ(ストリーム)を検知するメソッドを提供するクラスです。
わかりにくいとは思いますが、実際に実装をすることで少しづつ理解をしましょう。
基本実装(Java7)
Observableを使用したコードを実装します。
文字列リストをObservableで扱います。
そして、リストに格納したデータを、onNextメソッドで取りだします。
package java_lang_programming.com.android_reactivex_demo.ui; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.View; import android.widget.Button; import java.util.ArrayList; import java.util.List; import java_lang_programming.com.android_reactivex_demo.R; import rx.Observable; import rx.Observer; import rx.functions.Func1; /** * Observable Sample */ public class ObservableActivity extends AppCompatActivity { private static final String TAG = "ObservableActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_observable); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); Button observable_just_j7 = (Button) findViewById(R.id.observable_just_j7); observable_just_j7.setOnClickListener(view -> { observableJustJava7(); }); } /** * initialization */ private void initJustJava7() { Observable<List<String>> observable = Observable.just(getList()); observable.subscribe(new Observer<List<String>>() { @Override public void onCompleted() { Log.d(TAG, "observableJustJava7 onCompleted."); } @Override public void onError(Throwable e) { } @Override public void onNext(List<String> list) { Log.d(TAG, "observableJustJava7 onNext : list count :" + list.size()); } }); } }
■ 実装の解説
1. Observableオブジェクトの作成
Observable.just()でObservableオブジェクトを生成します。
Observable<List<String>> observable = Observable.just(getList());
ObserverインターフェースのonNextメソッドは、Observable.just()の引数を受け取ります。
@Override public void onNext(List<String> list) { Log.d(TAG, "observableJustJava7 onNext : list count :" + list.size()); }
2. subscribeメソッド
Observableオブジェクトからsubscribeメソッドを呼び出します。
observable.subscribe(new Observer<List<String>>() { @Override public void onCompleted() { Log.d(TAG, "initJustJava7 onCompleted."); } @Override public void onError(Throwable e) { } @Override public void onNext(List<String> list) { Log.d(TAG, "initJustJava7 onNext : list count :" + list.size()); } });
subscribeメソッドは、以下のメソッドを順に呼び出します。
- onNext
- onCompleted
onNextの処理が完了すると、onCompletedメソッドが呼び出されます。途中でエラーが起こるとonErrorメソッドが呼びだされます。
基本実装(Java8)
次に上記の処理をJava8で書き換えます。
Observableの機能は、Java8の機能を使うことで、よりシンプルに実装することができます。
package java_lang_programming.com.android_reactivex_demo.ui; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.View; import android.widget.Button; import java.util.ArrayList; import java.util.List; import java_lang_programming.com.android_reactivex_demo.R; import rx.Observable; import rx.Observer; import rx.functions.Func1; /** * Observable Sample */ public class ObservableActivity extends AppCompatActivity { private static final String TAG = "ObservableActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_observable); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); Button observable_just_j7 = (Button) findViewById(R.id.observable_just_j7); observable_just_j7.setOnClickListener(view -> { observableJustJava7(); }); +Button observable_just_j8 = (Button) findViewById(R.id.observable_just_j8); observable_just_j8.setOnClickListener(view -> { observableJustJava8(); }); } /** * initialization */ private void observableJustJava7() { Observable<List<String>> observable = Observable.just(getList()); observable.subscribe(new Observer<List<String>>() { @Override public void onCompleted() { Log.d(TAG, "observableJustJava7 onCompleted."); } @Override public void onError(Throwable e) { } @Override public void onNext(List<String> list) { Log.d(TAG, "observableJustJava7 onNext : list count :" + list.size()); } }); } +/** * initialization */ private void observableJustJava8() { Observable<List<String>> observable = Observable.just(getList()); observable.subscribe(list -> onNext(list), error -> onError(error), () -> onCompleted()); } /** * Get list * * @return */ private List<String> getList() { List<String> list = new ArrayList<String>(); list.add("suzuki"); list.add("sasaki"); list.add("sato"); return list; } /** * Get result * * @param list */ private void onNext(List<String> list) { Log.d(TAG, "observableJustJava8 onNext : list count :" + list.size()); } /** * Get Error * * @param e */ private void onError(Throwable e) { } /** * call complete */ private void onCompleted() { Log.d(TAG, "onCompleted."); } }
■ 実装の解説
1. subscribeメソッドの匿名クラスのラムダ式
subscribeメソッドの匿名クラスのインスタンスをラムダ式で書き換えます
Observable<List<String>> observable = Observable.just(getList()); observable.subscribe(list -> onNext(list), error -> onError(error), () -> onCompleted());
冗長だったコードがシンプルになりました。
記述方法が異なるだけで、処理はJava7と全く同じです。
ビルドと実行
実装を終えたら、ビルドしてアプリを実行します。
Java7で実行します。

コンソールログを確認します。
observableJustJava7 onNext : list count :3 observableJustJava7 onCompleted.
続いてJava8で実行します。

コンソールログを確認します。
observableJustJava8 onNext : list count :3 ObservableActivity: onCompleted.
うまく動きました。
まとめ
Observableを使うと、APIやSQLiteを使った非同期処理も手軽に実装できます。
少し学習コストは高いですが、見合った効果はあるので導入してみてください。
Java 8 のStream APIに慣れていれば、さらに習得は早いでしょう。
リアクティブプログラミング
ここから先は、リアクティブプログラミングの説明です。
Observableの使い方ではなく、リアクティブプログラミングを学習したい人が対象です。
考え方
リアクティブプログラミング(以下FRP)の学習で習得しなければならないのは、ストリームという考え方です。
この考え方は、従来のオブジェクト志向の考え方に慣れていると、最初は頭を悩ますかもしれません。
オブジェクト志向はデータを物として捉えます。UMLの記述は典型的なオブジェクト志向の考え方です。

FRPを考える場合は、ストリームでデータを捉えなければいけません。
ストリームは、データやイベントの流れです。
例えば、クリックイベントやイベントバスは、イベントストリームとして作成します。
変数、ユーザー入力、プロパティ、キャッシュ、データ構造などは、データストリームとして作成します。つまり、何でもストリームにして物を考えます。
これがFRPの特徴です。
この記事のサンプルコードをデータストリームで考えてみましょう。
s ---suzuki---sasaki---sato---
文字列リストのストリームを作成しています。sはstreamのsです。
RxJavaは、ストリームをObservableオブジェクトで表します。
この命名はわかりにくい表現ですが、慣れるしかありません。
このストリームを取得、つまり"listening"することをsubscribingと呼びます。
RxJavaの場合、このメソッドはsubscribe()です。このオブジェクト名とメソッド名の不明瞭さは、プログラマをFRPから遠ざける原因だと思います。
s ---suzuki---sasaki---sato--- ↓ subscribe() ↓ 結果 r ---suzuki---sasaki---sato---
rはresultのrです。
結果のストリームは、初期のストリームと同じです。なぜなら、ストリームのデータは加工していません。
RxJavaの場合、結果はonNext()で受け取ります。
subscribe()でストリームを取得(観察)しにいって、onNext()で加工されたデータを排出するということを理解してください。
非同期
本格的にリアクティブプログラミングを学習するなら、マルチスレッドをきっちり学習することをお勧めします。
その際は、以下の書籍をお勧めします。
書籍名がデザインパターン入門となっていますが、スレッドを基本から説明した本です。デザインパターンと命名したのは、ベストセラーの姉妹本のせいでしょう。とてもわかりやすい良書なので、手元に置いておくと良いでしょう。
余力がある人、プログラミングに自信がある人は、以下を合わせて読むと、さらに良いと思います。
書籍を読んで、コーディングをするという作業を徹底的に繰り返してください。リアクティブプログラミングは、アプリ作成の大きな力となるはずです。