[Android] RxJavaのストリームで複数種の値を流す(Tuple)

  • 14
    Like
  • 6
    Comment
More than 1 year has passed since last update.

メソッドの返り値の型を Observable<T> でくるむようにアプリケーション開発していたりすると、要件によってはストリームに複数種の値を流したくなることがあります。

Java(Android) に Tuple は無いのですが、任意の型かつ複数種の値を保持できるクラスを独自に用意しておくと便利です。

例として2つの値を扱う場合は次のようになります。

Tuple2.java
public class Tuple2<T1, T2> {
    private final T1 t1;
    private final T2 t2;

    private Tuple2(T1 t1, T2 t2) {
        this.t1 = t1;
        this.t2 = t2;
    }

    public T1 get1() {
        return t1;
    }

    public T2 get2() {
        return t2;
    }

    public static <T1, T2> Tuple2<T1, T2> create(T1 t1, T2 t2) {
        return new Tuple2<>(t1, t2);
    }
}

利用例

例として、返り値が Observable なメソッドで List<String>Integer を返すコードは次のようになります。

Java 8 と Retrolambda を利用しています。

public Observable<Tuple2<List<String>, Integer>> getSomeAsync() {
    return Observable.create(subs -> {

        List<String> list = new ArrayList<>();
        list.add("abc");
        list.add("efg");
        list.add("hij");

        subs.onNext(Tuple2.create(list, 999));
        subs.onCompleted();
    });
}

値の取り出しは次のようになります。

getSomeAsync().subscribe(aListIntegerTuple2 -> {

    Log.d("tuple:1", aListIntegerTuple2.get1().get(0)+""); // abc が出力される

    Log.d("tuple:2", aListIntegerTuple2.get2()+""); // 999 が出力される

});

ちなみに私は Retrolambda を使う場合、型が分からなくなるので上記のように a型名 のような変数名をつけるようにしています。

ほか

同様に Tuple3 Tuple4 は次のようになります。

Tuple3.java
public class Tuple3<T1, T2, T3> {
    private final T1 t1;
    private final T2 t2;
    private final T3 t3;

    private Tuple3(T1 t1, T2 t2, T3 t3) {
        this.t1 = t1;
        this.t2 = t2;
        this.t3 = t3;
    }

    public T1 get1() {
        return t1;
    }

    public T2 get2() {
        return t2;
    }

    public T3 get3() {
        return t3;
    }

    public static <T1, T2, T3> Tuple3<T1, T2, T3> create(T1 t1, T2 t2, T3 t3) {
        return new Tuple3<>(t1, t2, t3);
    }
}
Tuple4.java
public class Tuple4<T1, T2, T3, T4> {
    private final T1 t1;
    private final T2 t2;
    private final T3 t3;
    private final T4 t4;

    private Tuple4(T1 t1, T2 t2, T3 t3, T4 t4) {
        this.t1 = t1;
        this.t2 = t2;
        this.t3 = t3;
        this.t4 = t4;
    }

    public T1 get1() {
        return t1;
    }

    public T2 get2() {
        return t2;
    }

    public T3 get3() {
        return t3;
    }

    public T4 get4() {
        return t4;
    }

    public static <T1, T2, T3, T4> Tuple4<T1, T2, T3, T4> create(T1 t1, T2 t2, T3 t3, T4 t4) {
        return new Tuple4<>(t1, t2, t3, t4);
    }
}