RxJava - 获取列表中的每一项

RxJava - fetch every item on the list

我有一个方法 returns 一个 Observable<ArrayList<Long>>,它们是一些项目的 ID。我想浏览此列表并使用 returns Observable<Item>.

的另一种方法下载每个项目

我如何使用 RxJava 运算符来做到这一点?

这是一个独立的小例子

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>

使用修改源 Observable 的 Transformer,用函数调用 flatMap。您可以将此视为一个两步过程:

  1. 该函数获取每个发出的项目(Iterable<T>)并将其作为 Observable<T>
  2. 重新发出
  3. flatMap 获取每个发出的 Observable<T> 对象并将它们合并为一个 Observable<T>

变形金刚看起来像这样:

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);
            }
        });
    }
}

创建转换器后,您可以使用 compose 将转换应用于源可观察对象:

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);
        }
    };
}

使用 composeTransformer 而不是 flatMapFunc1 的好处是,如果将来您需要展平列表同样,您甚至不必考虑使用哪个运算符(map?flatMap?concatMap?)。换句话说,平面图操作被烘焙到 FlattenTransform class 并且该细节被抽象掉了。

变形金刚还有其他好处,例如能够将多个操作链接在一起。

作为 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: Returns 一个 Observable,它将源 ObservableSource 发出的每个项目与对应于生成的项目的 Iterable 中的值合并通过选择器。

使用方法引用如下所示:

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

在 Kotlin 中使用 flattenAsFlowable:

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

对于 Kotlin

 Observable
        .fromIterable(listOfChallenges) // list of challenges which contain challenge ID
        .flatMap { eachChallenge ->
            getChallengeDetail(eachChallenge.challengeUid!!) // fetch details of each challenge
        }
        .toList() // map to list
        .subscribe({ listOfEachChallengesDetail ->

        }, {
            // error
        })