web-dev-qa-db-ja.com

RxJava-リスト上のすべてのアイテムを取得します

いくつかのアイテムのIDであるObservable<ArrayList<Long>>を返すメソッドがあります。このリストを調べて、Observable<Item>を返す別のメソッドを使用してすべてのアイテムをダウンロードしたいと思います。

RxJava演算子を使用してこれを行うにはどうすればよいですか?

39
k_wisniewski

これは小さな自己完結型の例です

_public class Example {

    public static class Item {
        int id;
    }

    public static void main(String[] args) {
        getIds()
                .flatMapIterable(ids -> ids) // Converts your list of ids into an Observable which emits every item in the list
                .flatMap(Example::getItemObservable) // Calls the method which returns a new Observable<Item>
                .subscribe(item -> System.out.println("item: " + item.id));
    }

    // Simple representation of getting your ids.
    // Replace the content of this method with yours
    private static Observable<List<Integer>> getIds() {
        return Observable.just(Arrays.<Integer>asList(1, 2, 3));
    }

    // Replace the content of this method with yours
    private static Observable<Item> getItemObservable(Integer id) {
        Item item = new Item();
        item.id = id;
        return Observable.just(item);
    }
}
_

Observable.just(Arrays.<Integer>asList(1, 2, 3))は質問からの_Observable<ArrayList<Long>>_の単純な表現であることに注意してください。コード内の独自のObservableに置き換えることができます。

これにより、必要なものの基礎が得られます。

p/s:以下の説明のようにflatMapIterableに属するため、この場合はIterableメソッドを使用します:

_/**
 * Implementing this interface allows an object to be the target of
 * the "for-each loop" statement. See
 * <strong>
 * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides /language/foreach.html">For-each Loop</a>
 * </strong>
 *
 * @param <T> the type of elements returned by the iterator
 *
 * @since 1.5
 * @jls 14.14.2 The enhanced for statement
  */
 public interface Iterable<T>
_
51
Miguel Lavigne

flatMapIterableの代替として、これを flatMap で実行できます。

_Observable.just(Arrays.asList(1, 2, 3)) //we create an Observable that emits a single array
            .flatMap(numberList -> Observable.fromIterable(numberList)) //map the list to an Observable that emits every item as an observable
            .flatMap(number -> downloadFoo(number)) //download smth on every number in the array
            .subscribe(...);


private ObservableSource<? extends Integer> downloadFoo(Integer number) {
   //TODO
}
_

個人的には、.flatMap(numberList -> Observable.fromIterable(numberList)).flatMapIterable(numberList -> numberList )よりも読みやすく、理解しやすいと思います。

違いは順序(RxJava2)のようです:

  • Observable.fromIterable:Iterableシーケンスを、シーケンス内のアイテムを出力するObservableSourceに変換します。
  • Observable.flatMapIterable:セレクターによって生成されたアイテムに対応するIterableの値とソースObservableSourceによって発行された各アイテムをマージするObservableを返します。

メソッド参照を使用すると、次のようになります。

_Observable.just(Arrays.asList(1, 2, 3))
            .flatMap(Observable::fromIterable)
            .flatMap(this::downloadFoo)
_
5
patrickf

Transformer を使用して、ソースObservableを変更し、関数でflatMapを呼び出します。これは2段階のプロセスと考えることができます。

  1. この関数は、発行された各アイテム(Iterable<T>)を受け取り、Observable<T>として再発行します
  2. flatMapは、これらの放出されたObservable<T>オブジェクトをそれぞれ取り、それらを単一のObservable<T>にマージします

Transformerは次のようになります。

public class FlattenTransform<T> implements Observable.Transformer<Iterable<T>, T> {
    @Override
    public Observable<? extends T> call(Observable<? extends Iterable<T>> source) {
        return source.flatMap(new Func1<Iterable<T>, Observable<T>>() {
            @Override
            public Observable<T> call(Iterable<T> values) {
                return Observable.from(values);
            }
        });
    }
}

Transformerを作成したら、composeを使用して、ソースobservableに変換を適用できます。

public class Example {

    private static final ArrayList<Long> sourceList = new ArrayList<>(Arrays.asList(new Long[] {1L,2L,3L}));
    private static final Observable<ArrayList<Long>> listObservable = Observable.just(sourceList);
    private static final FlattenTransform<Long> flattenList = new FlattenTransform<Long>();

    public static void main(String[] args) {
        listObservable.compose(flattenList).subscribe(printItem);
    }

    private static Action1<Long> printItem = new Action1<Long>() {
        @Override
        public void call(Long item) {
            System.out.println("item: " + item);
        }
    };
}

composeTransformerFunc1の代わりにflatMapで使用する利点は、将来リストをフラット化する必要がある場合、使用する演算子についても考える必要があります(map?flatMap?concatMap?)。つまり、flatmap操作はFlattenTransformクラスにベイクされ、その詳細は抽象化されます。

トランスフォーマーには、複数の操作を連結できるなど、他の利点もあります。

4
weefbellington

KotlinではflattenAsFlowableを使用します。

repository.getFlowableData(id)
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.computation())
    .toList()
    .flattenAsFlowable { it }
    .map { someMethod(it) }
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ },
        { onError(it) })
1
CoolMind