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

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

Androidアプリ開発でRxJavaを使うと、AndroidでもJava8的な文法を利用できます。さらに、 クラス間の通知処理を少ないコード量で記述することができます。
この記事は、AndroidアプリでRxJavaのBehaviorSubjectを使う方法を記載した記事です。

環境はAndroid 7.1 (API level 25) です。

環境

  • OS X El Capitan
  • Oracle jdk version 1.8.0_72
  • Android Studio 2.2.2
  • android sdk 25
  • rxandroid:1.2.1
  • rxjava:1.1.6

難易度

中級者向け

サンプルコード

Android-ReactiveX-Demo

関連記事

BehaviorSubject

BehaviorSubjectは、onNextで渡された値を保持し、subscribe()した直後に保持していた値を流します。

BehaviorSubject

基本実装(Java7)

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

サンプルでは、文字列を扱います。

{project_folder}/ui/BehaviorSubjectActivity
package java_lang_programming.com.android_reactivex_demo.ui;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java_lang_programming.com.android_reactivex_demo.R;
import rx.Observer;
import rx.subjects.BehaviorSubject;

/**
 * BehaviorSubject Sample
 */
public class BehaviorSubjectActivity extends AppCompatActivity {

    BehaviorSubject<String> behaviorSubject = BehaviorSubject.create();

    private TextView result;
    private EditText text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_behavor_subject);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        result = (TextView) findViewById(R.id.result);
        text = (EditText) findViewById(R.id.text);

        Button behavior_subject = (Button) findViewById(R.id.behavior_subject);
        behavior_subject.setOnClickListener(view -> behavior_subject_java_7());
        behavior_subject_java_7_init();

    }

    /**
     * initialize
     */
    private void behavior_subject_java_7_init() {
        behaviorSubject.subscribe(
                new Observer<String>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(String strings) {
                        result.setText(result.getText().toString() + strings);
                    }
                });
    }

    /**
     * 実行
     */
    private void behavior_subject_java_7() {
        behaviorSubject.onNext(text.getText().toString());
    }

}
        

■ 実装の解説

1. BehaviorSubjectオブジェクトの作成

BehaviorSubject.create()でBehaviorSubjectオブジェクトを作成します。

BehaviorSubject<String> behaviorSubject = BehaviorSubject.create();
        

BehaviorSubject.create()は、保持するデータを設定します。このサンプルは、String型のデータです。
また、create()の引数に初期値を設定することもできます。初期値は以下のように実装します。

BehaviorSubject behaviorSubject = BehaviorSubject.create("example");
        

2. subscribeメソッド

subscribeメソッドはデータの流れをリスニングすることができます。つまり、データの変更を受け取れます。このサンプルでは、behaviorSubjectオブジェクトがデータに該当します。

subscribeメソッドの引数には、Observerインターフェースを設定します。Observerインターフェースは、onCompleted(), onError(Throwable e), void onNext(T t)の3つのメソッドを実装する必要があります。このサンプルは、匿名クラスで実装します。

behaviorSubject.subscribe(
        new Observer<String>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(String strings) {
                result.setText(result.getText().toString() + strings);
            }
        });
        

BehaviorSubjectオブジェクトは、onNext()を呼び出すことでeventを受け取れます。
さらに、subscribeメソッドは、以下のメソッドを呼び出します。

  • onNext()
  • onCompleted()
  • onError()

途中でエラーが起こるとonError()メソッドが呼びだされます。onCompletedメソッドを呼びだすと、通知が終了します。その後にonNext()を呼び出しても、onNext()は呼び出されません。

3. onNextメソッド

ボタン押下時にonNextメソッドを実行します。
onNextメソッドは、引数で受け取った値を放出します。

private void behavior_subject_java_7() {
    behaviorSubject.onNext(text.getText().toString());
}
        

上記は、テキストに設定した値を放出しています。イベントの流れは、

-----  onNext(text.getText().toString())
        

です。

ビルドと実行

実装を終えたら、ビルドしてアプリを実行します。

BehaviorSubject

EditTextに入力されている文字列が、TextViewに追加されています。

distinctUntilChanged

BehaviorSubjectは、distinctUntilChangedメソッドと一緒に利用する機会が多いと思います。
distinctUntilChangedメソッドは呼んで字のごとく、値が変化した時だけsubscribeメソッドを実行することができます。

{project_folder}/ui/ObservableActivity
package java_lang_programming.com.android_reactivex_demo.ui;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java_lang_programming.com.android_reactivex_demo.R;
import rx.Observer;
import rx.subjects.BehaviorSubject;

/**
 * BehaviorSubject Sample
 */
public class BehaviorSubjectActivity extends AppCompatActivity {

    BehaviorSubject<String> behaviorSubject = BehaviorSubject.create();
    BehaviorSubject<String> behaviorSubjectDistinct = BehaviorSubject.create();

    private TextView result;
    private EditText text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_behavor_subject);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        result = (TextView) findViewById(R.id.result);
        text = (EditText) findViewById(R.id.text);

        Button behavior_subject = (Button) findViewById(R.id.behavior_subject);
        behavior_subject.setOnClickListener(view -> behavior_subject_java_7());
        behavior_subject_java_7_init();
        behavior_subject_distinct_java_7_init();
        //behavior_subject_interval_java_7_init();

        Button behavior_subject_distinctUntilChanged = (Button) findViewById(R.id.behavior_subject_distinctUntilChanged);
        behavior_subject_distinctUntilChanged.setOnClickListener(view -> behavior_subject_distinctUntilChanged_java_7());
    }

    /**
     * initialize
     */
    private void behavior_subject_java_7_init() {
        behaviorSubject.subscribe(
                new Observer<String>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(String strings) {
                        result.setText(result.getText().toString() + strings);
                    }
                });
    }

    /**
     * initialize
     */
    private void behavior_subject_distinct_java_7_init() {
        behaviorSubjectDistinct.distinctUntilChanged().subscribe(
                new Observer<String>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(String strings) {
                        result.setText(result.getText().toString() + strings);
                    }
                });
    }

    /**
     * 実行
     */
    private void behavior_subject_java_7() {
        behaviorSubject.onNext(text.getText().toString());
    }

    /**
     * 実行
     */
    private void behavior_subject_distinctUntilChanged_java_7() {
        behaviorSubjectDistinct.onNext(text.getText().toString());
    }

}
        

■ 実装の解説

1. distinctUntilChanged()

BehaviorSubjectオブジェクトからdistinctUntilChanged()メソッドを呼び出します。

behaviorSubjectDistinct.distinctUntilChanged()
        

distinctUntilChanged()onNext()から渡される値が変更になった場合だけ呼びだされます。

ビルドと実行

実装を終えたら、ビルドしてアプリを実行します。

Java7で実行します。

distinctUntilChanged

入力文字が変更された時だけ処理が実行されています。

その他の仕様

その他、開発で理解しておくべきBehaviorSubjectの仕様を以下に示します。

1. String型で初期値なし

{project_folder}/ui/ObservableActivity
BehaviorSubject<String> behaviorSubject = BehaviorSubject.create();
Log.d(TAG, "BehaviorSubject : " + behaviorSubject.getValue());
       

出力結果

console
BehaviorSubject : null
       

2. String型で初期値あり

{project_folder}/ui/ObservableActivity
BehaviorSubject<String> behaviorSubject = BehaviorSubject.create("sample");
Log.d(TAG, "BehaviorSubject : " + behaviorSubject.getValue());
       

出力結果

console
BehaviorSubject : sample
       

3. Boolean型で初期値なし

{project_folder}/ui/ObservableActivity
BehaviorSubject<Boolean> behaviorSubject = BehaviorSubject.create();
Log.d(TAG, "BehaviorSubject : " + behaviorSubject.getValue());
       

出力結果

console
BehaviorSubject : null
       

4. Boolean型で初期値あり

{project_folder}/ui/ObservableActivity
BehaviorSubject<Boolean> behaviorSubject = BehaviorSubject.create("false");
Log.d(TAG, "BehaviorSubject : " + behaviorSubject.getValue());
       

出力結果

console
BehaviorSubject : false
       

まとめ

BehaviorSubjectを使うと、値の管理が手軽に実装できます。
最初はとっつきにくいですが、慣れてくると手放せなくなるくらい便利です。

関連記事

タグ検索で調べてみよう

Android7.0 RxJava Java8