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

2016年09月07日(編集2016年10月02日)
このエントリーをはてなブックマークに追加

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

難易度

中級者向け

サンプルコード

Android-ReactiveX-Demo

RxJava

RxJavaとはリアクティブプログラミングをおこなうライブラリであるReactive ExtensionsのJava VM実装です。

Observable

Observableは、Observableへsubscribingするためのメソッドを提供します。
乱暴に言うと、Observableは監視対象のデータを設定し、そのデータの流れ(ストリーム)を検知するメソッドを提供するクラスです。

わかりにくいとは思いますが、実際に実装をすることで少しづつ理解をしましょう。

基本実装(Java7)

Observableを使用したコードを実装します。

文字列リストをObservableで扱います。
そして、リストに格納したデータを、onNextメソッドで取りだします。

{project_folder}/ui/ObservableActivity.java
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の機能を使うことで、よりシンプルに実装することができます。

{project_folder}/ui/ObservableActivity
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で実行します。

Java7

コンソールログを確認します。

console
observableJustJava7 onNext : list count :3
observableJustJava7 onCompleted.
        

続いてJava8で実行します。

Java8

コンソールログを確認します。

console
observableJustJava8 onNext : list count :3
ObservableActivity: onCompleted. 
        

うまく動きました。

まとめ

Observableを使うと、APIやSQLiteを使った非同期処理も手軽に実装できます。
少し学習コストは高いですが、見合った効果はあるので導入してみてください。
Java 8 のStream APIに慣れていれば、さらに習得は早いでしょう。

リアクティブプログラミング

ここから先は、リアクティブプログラミングの説明です。
Observableの使い方ではなく、リアクティブプログラミングを学習したい人が対象です。

考え方

リアクティブプログラミング(以下FRP)の学習で習得しなければならないのは、ストリームという考え方です。
この考え方は、従来のオブジェクト志向の考え方に慣れていると、最初は頭を悩ますかもしれません。
オブジェクト志向はデータを物として捉えます。UMLの記述は典型的なオブジェクト志向の考え方です。

UMLクラス図

FRPを考える場合は、ストリームでデータを捉えなければいけません。

Stream

ストリームは、データやイベントの流れです。

例えば、クリックイベントやイベントバスは、イベントストリームとして作成します。
変数、ユーザー入力、プロパティ、キャッシュ、データ構造などは、データストリームとして作成します。つまり、何でもストリームにして物を考えます。
これがFRPの特徴です。

この記事のサンプルコードをデータストリームで考えてみましょう。

stream
s ---suzuki---sasaki---sato---
        

文字列リストのストリームを作成しています。sはstreamのsです。

RxJavaは、ストリームをObservableオブジェクトで表します。
この命名はわかりにくい表現ですが、慣れるしかありません。

このストリームを取得、つまり"listening"することをsubscribingと呼びます。
RxJavaの場合、このメソッドはsubscribe()です。このオブジェクト名とメソッド名の不明瞭さは、プログラマをFRPから遠ざける原因だと思います。

stream
s ---suzuki---sasaki---sato---
      ↓ subscribe()
      ↓ 結果
r ---suzuki---sasaki---sato---
        

rはresultのrです。
結果のストリームは、初期のストリームと同じです。なぜなら、ストリームのデータは加工していません。
RxJavaの場合、結果はonNext()で受け取ります。
subscribe()でストリームを取得(観察)しにいって、onNext()で加工されたデータを排出するということを理解してください。

非同期

本格的にリアクティブプログラミングを学習するなら、マルチスレッドをきっちり学習することをお勧めします。
その際は、以下の書籍をお勧めします。

書籍名がデザインパターン入門となっていますが、スレッドを基本から説明した本です。デザインパターンと命名したのは、ベストセラーの姉妹本のせいでしょう。とてもわかりやすい良書なので、手元に置いておくと良いでしょう。

余力がある人、プログラミングに自信がある人は、以下を合わせて読むと、さらに良いと思います。

書籍を読んで、コーディングをするという作業を徹底的に繰り返してください。リアクティブプログラミングは、アプリ作成の大きな力となるはずです。

関連記事

タグ検索で調べてみよう

Android7.0 RxJava Java8