RxJava + Androidの世界に入門する

RxJavaに入門するためのあれこれを書いておきます。

RxJavaの導入

まずはプロジェクトにRxJavaを導入します。

Module: appのbuild.gradleを開き、dependenciesにRxJavaを追加します。Android Studio 2系の場合はimplementationではなくcompileでしょうか。

dependencies {
    //RxJava
    implementation 'io.reactivex.rxjava2:rxjava:2.1.9'
}

また、Java8から導入されたラムダ式を使いたいので、Java8を有効にします。

android {
    compileOptions {
        targetCompatibility 1.8
        sourceCompatibility 1.8
    }
}

Android Studio 3系はラムダ式をサポートしているようですが、Android Studio 2系はラムダ式をサポートしていません。Android Studio 2系の場合はラムダ式をバックポートしてくれる「Retrolambda」というライブラリを使います。Retrolambdaの導入については以下の記事を参考にしてください。

AndroidのプロジェクトにRetrolambdaを導入する – Androidアプリ開発@つくば

Hello RxJava

まずはRxJavaを使ってHello World的なことを行ってみましょう。今回は適当にonCreateの中に書きます。まずはObservableを作って、subscribeします。Observableは、java.utilのものとio.reactivexのものがあるので、io.reactivexの方を使います。最初だけ、コードのほぼ全文を示しておきます。実行してみましょう。

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import io.reactivex.Observable;

public class MainActivity extends AppCompatActivity {

    private final String TAG = getClass().getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Observable.just("Hello, RxJava!")
                .subscribe(string -> Log.d(TAG, string));
    }
}

「Hello, RxJava!」とLogcatに表示されたでしょうか?

Observableを作って、subscribeする。これがRxJavaの基本形になります。just()はObservableを作るメソッドの一つで、引数にとったオブジェクトが流れていきます。もっと多くのものを流してみましょう。

Observable.just(0, 1, 2, 3, 4)
        .subscribe(i -> Log.d(TAG, String.valueOf(i)));

0、1、2、3、4のintが流れていきます。intが流れているので、String.valueOf()でString型に変換しています。just()は、10個までの引数をとり、それを流してくれるオペレーターです。引数の型は問いません。例えば以下のコードも問題なく動作します。

Observable.just(0, 'a', 1, 'b', 2, "Hello!")
        .subscribe(__ -> {
            //do something here
        });

10個以上の要素を流したい時はどうしたらいいでしょうか?Observable.fromArray()やObservable.fromIterable()を使いましょう。

List list = new ArrayList<>();
for (int i = 0; i < 20; i++) {
    list.add(i);
}
Observable.fromIterable(list)
        .subscribe(i -> Log.d(TAG, String.valueOf(i)));

これで0〜19までの数字が流れていきます。ところで、上記のコードは少し残念な感じです。せっかくRxJavaを使っているのに、for文を使っています。上記のコードはrange()を使って置き換えることができます。

Observable.range(0, 19)
        .subscribe(i -> Log.d(TAG, String.valueOf(i)));

この流れの中から、偶数の数字のみを取り出してみます。filter()を使いましょう。

Observable.range(0, 19)
        .filter(i -> i % 2 == 0)
        .subscribe(i -> Log.d(TAG, String.valueOf(i)));

filter()は、ラムダ式の返り値がtrueとなるもののみ通します。文字通りフィルターしてくれるオペレータです。使用頻度が高いです。

次にフィルターした値を10倍にして流してみます。map()を使います。

Observable.range(0, 19)
        .filter(i -> i % 2 == 0)
        .map(i -> i * 10)
        .subscribe(i -> Log.d(TAG, String.valueOf(i)));

map()は変換を司っています。同じ型の値を流す必要さえありません。さらにint型をString型に変換して流してみましょう。

Observable.range(0, 19)
        .filter(i -> i % 2 == 0)
        .map(i -> i * 10)
        .map(i -> String.valueOf(i))
        .subscribe(s -> Log.d(TAG, s));

このように、オペレータはいくつでも好きなように繋げることができます。RxJavaでは、オペレータを組み合わせることによって様々なことを簡潔なコードで実現することができます。

ところで、上記のコードは「メソッド参照」によってもう少し簡潔に書くことができます。やってみましょう。

Observable.range(0, 19)
        .filter(i -> i % 2 == 0)
        .map(i -> i * 10)
        .map(String::valueOf)
        .subscribe(s -> Log.d(TAG, s));

長くなってきたので、この記事は一度この辺で終わりにします。Observableを作って、subscribeする。流れを作る。オペレータで流れを変える。この感覚が、少しでも伝わったら良いのですが。

本文書は、筆者の理解が深まるとともに加筆・修正していこうと思います。突っ込みがあれば、コメント欄またはツイッターまで。お手柔らかによろしくお願いします。

茨城県つくば市在住のイケてるメンズです。東京工業大学卒業後、コンサルタントを経て、2016年よりモバイルアプリ(主にAndroid)のエンジニアとして働いています。2017年UI DesignコンテストAndroid部門特別賞受賞。

ご連絡はメールフォームからお願いします。