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

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

Androidアプリ開発でRxJavaを使うと、AndroidでもJava8的な文法を利用できます。さらには、API等を使った非同期処理を少ないコード量で記述することができます。
この記事は、AndroidアプリでRxJavaのObservable mapを使う方法を記載した記事です。

環境は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

前回記事

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

map

mapはストリームに流れてくるアイテムを変換します。

map

Java 8のStreamのmapと同等の機能を提供します。

基本実装(Java7)

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

サンプルでは、文字列リストデータをObservableで扱います。

{project_folder}/ui/ObservableMapActivity
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.util.Log;
import android.widget.Button;
import android.widget.TextView;

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;

public class ObservableMapActivity extends AppCompatActivity {

    private static final String TAG = "ObservableMapActivity";

    TextView result;
    int countSuzuki;

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

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

        Button observable_from_map_j7 = (Button) findViewById(R.id.observable_from_map_j7);
        observable_from_map_j7.setOnClickListener(view -> initFromMapJava7());
    }

    /**
     * observable from map sample for java 7
     */
    private void initFromMapJava7() {
        countSuzuki = 0;
        Observable<String> observable = Observable.from(getList());
        observable.map(new Func1<String, Integer>() {
            @Override
            public Integer call(String str) {
                if (str.equals("suzuki")) {
                    return 1;
                }
                return 0;
            }
        }).subscribe(new Observer<Integer>() {

            @Override
            public void onCompleted() {
                Log.d(TAG, "initFromMapJava7 onCompleted.");
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Integer integer) {
                Log.d(TAG, "initFromMapJava7 onNext : integer :" + integer);
                countSuzuki = countSuzuki + integer;
                result.setText(String.valueOf(countSuzuki));
            }
        });
    }

    /**
     * Get list
     *
     * @return
     */
    private List<String> getList() {
        List<String> list = new ArrayList<String>();
        list.add("suzuki");
        list.add("sasaki");
        list.add("sato");
        return list;
    }

}
        

■ 実装の解説

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

Observable.from()でObservablオブジェクトを作成します。

Observable<String> observable = Observable.from(getList());
        

Observable.from()は、Iterable(反復可能)なデータを設定します。つまり、for文で利用できるデータです。
また、from()は現在のスレッドで実行されます

2. mapメソッド

mapメソッドの引数は、匿名クラスのインスタンスメソッドを呼び出します。

@Override
public Integer call(String str) {
    if (str.equals("suzuki")) {
        return 1;
    }
    return 0;
}
        

3. subscribeメソッド

subscribeメソッドの引数は、匿名メソッドの関数を呼び出します。

subscribe(new Observer<Integer>() {
      @Override
      public void onCompleted() {
          Log.d(TAG, "initFromMapJava7 onCompleted.");
      }

      @Override
      public void onError(Throwable e) {

      }

      @Override
      public void onNext(Integer integer) {
          Log.d(TAG, "initFromMapJava7 onNext : integer :" + integer);
          countSuzuki = countSuzuki + integer;
          result.setText(String.valueOf(countSuzuki));
      }
  });
        

subscribeメソッドは、以下のメソッドをIteratorの数だけ順に呼び出します。

  • call()
  • onNext()

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.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;

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;

public class ObservableMapActivity extends AppCompatActivity {

    private static final String TAG = "ObservableMapActivity";

    TextView result;
    int countSuzuki;

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

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

        Button observable_from_map_j7 = (Button) findViewById(R.id.observable_from_map_j7);
        observable_from_map_j7.setOnClickListener(view -> initFromMapJava7());

        Button observable_from_map_j8 = (Button) findViewById(R.id.observable_from_map_j8);
        observable_from_map_j8.setOnClickListener(view -> initFromMapJava8());
    }

    /**
     * observable from map sample for java 7
     */
    private void initFromMapJava7() {
        countSuzuki = 0;
        Observable<String> observable = Observable.from(getList());
        observable.map(new Func1<String, Integer>() {
            @Override
            public Integer call(String str) {
                Log.d(TAG, "initFromMapJava7 call");
                if (str.equals("suzuki")) {
                    return 1;
                }
                return 0;
            }
        }).subscribe(new Observer<Integer>() {

            @Override
            public void onCompleted() {
                Log.d(TAG, "initFromMapJava7 onCompleted.");
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Integer integer) {
                Log.d(TAG, "initFromMapJava7 onNext : integer :" + integer);
                countSuzuki = countSuzuki + integer;
                result.setText(String.valueOf(countSuzuki));
            }
        });
    }

   +/**
     * observable from map sample for java 8
     */
    private void initFromMapJava8() {
        countSuzuki = 0;
        Observable<String> observable = Observable.from(getList());
        observable.map(str -> call(str)).subscribe(integer -> onNext(integer), error -> onError(error), () -> onCompleted());
    }

    /**
     * observable from map call for java 8
     *
     * @param str
     * @return
     */
    public Integer call(String str) {
        Log.d(TAG, "initJustMapJava8 call");
        if (str.equals("suzuki")) {
            return 1;
        }
        return 0;
    }

    /**
     * Get Error
     *
     * @param e
     */
    private void onError(Throwable e) {

    }

    /**
     * call complete
     */
    private void onCompleted() {
        Log.d(TAG, "onCompleted.");
    }

    /**
     * Get result
     *
     * @param integer
     */
    private void onNext(Integer integer) {
        Log.d(TAG, "initFromMapJava8 onNext : integer :" + integer);
        countSuzuki = countSuzuki + integer;
        result.setText(String.valueOf(countSuzuki));
    }

    /**
     * Get list
     *
     * @return
     */
    private List<String> getList() {
        List<String> list = new ArrayList<String>();
        list.add("suzuki");
        list.add("sasaki");
        list.add("sato");
        return list;
    }

}
        

■ 実装の解説

1. mapメソッドラムダ式

mapメソッドの引数は、匿名メソッドの関数を呼び出します。

observable.map(str -> call(str))
        

文字列引数をcallメソッドに渡して、Integerオブジェクトを受けとっています。

2. subscribeメソッドの匿名クラスのインスタンスのラムダ式

subscribeメソッド引数の匿名クラスのインスタンスをラムダ式で書き換えます

subscribe(integer -> onNext(integer), error -> onError(error), () -> onCompleted());
        

記述方法が異なるだけで、処理はJava7と全く同じです。
ラムダ式でonNext(integer), onError(error), () -> onCompleted()と3つのメソッドを呼んでいます。

ビルドと実行

実装を終えたら、ビルドしてアプリを実行します。
コンソールログを確認します。

Java7で実行します。

Java 7

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

console
initFromMapJava7 call
initFromMapJava7 onNext : integer :1
initFromMapJava7 call
initFromMapJava7 onNext : integer :0
initFromMapJava7 call
onNext : integer :0
initFromMapJava7 onCompleted.
        

続いてJava8で実行します。

Java 8
console
initJustMapJava8 call
initFromMapJava8 onNext : integer :1
initJustMapJava8 call
initFromMapJava8 onNext : integer :0
initJustMapJava8 call
initFromMapJava8 onNext : integer :0
onCompleted.
        

うまく動きました。

まとめ

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

関連記事

タグ検索で調べてみよう

Android7.0 RxJava Java8