RxJava - 获取列表中的每个项目

46

我有一个返回 Observable<ArrayList<Long>> 的方法,这些是一些项的id。我想通过另一个返回Observable<Item>的方法遍历此列表并下载每个项。

如何使用RxJava操作符来完成这个任务?


排序是否重要? - lopar
2
不是真的,但出于教育目的,我真的很想看到两个版本。 - k_wisniewski
5个回答

59

这是一个简短的自包含示例

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。这应该是您所需的基础。
附注:针对此情况,请使用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>

2
你也可以使用Observable.from(Arrays.<Integer>asList(...)),而不需要使用flatMapIterable。 - lopar

11

使用 flatMap 作为 flatMapIterable 的替代方案:

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:返回一个Observable,该Observable将源ObservableSource发出的每个项目与由选择器生成的对应于该项目的Iterable中的值合并。

使用方法引用的示例如下:

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

请查看此问题:https://stackoverflow.com/questions/48959354/how-to-convert-from-observablelistx-to-observablelisty-using-a-function - Ehtesham Hasan

4
使用修改源Observable的转换器,并在其上调用flatMap函数。您可以将其视为一个两步骤过程:
  1. 该函数接受每个发出的项(一个Iterable<T>),并将其重新发出为一个Observable<T>
  2. 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);
            }
        });
    }
}

一旦您创建了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);
        }
    };
}

使用 Transformercompose 而不是 Func1flatMap 的优点在于,如果将来需要再次展开列表,您甚至不必考虑使用哪个操作符(map?flatMap?concatMap?)。换句话说,flatmap 操作已经嵌入到 FlattenTransform 类中,这个细节被抽象化了。

Transformer 还有其他好处,例如能够链接多个操作。


4
在Kotlin中使用flattenAsFlowable
repository.getFlowableData(id)
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.computation())
    .toList()
    .flattenAsFlowable { it }
    .map { someMethod(it) }
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ },
        { onError(it) })

2

针对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
        })

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接