【问题标题】:RxJava - fetch every item on the listRxJava - 获取列表中的每一项
【发布时间】:2015-01-19 23:08:03
【问题描述】:

我有一个返回Observable<ArrayList<Long>> 的方法,它是一些项目的ID。我想浏览这个列表并使用另一种返回 Observable<Item> 的方法下载每个项目。

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

【问题讨论】:

  • 订购重要吗?
  • 不是真的,但出于教育目的真的很喜欢看两个版本

标签: java monads reactive-programming rx-java


【解决方案1】:

这是一个独立的小例子

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.&lt;Integer&gt;asList(1, 2, 3)) 是您问题中Observable&lt;ArrayList&lt;Long&gt;&gt; 的简单表示。您可以在代码中将其替换为您自己的 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.from(Arrays.asList(...)) 而不需要 flatMapIterable
  • 你救了我的命。谢谢。
  • 很好的例子。谢谢。
  • @Miguel 你能看看这个问题吗? stackoverflow.com/questions/48959354/…
【解决方案2】:

作为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 -&gt; Observable.fromIterable(numberList)).flatMapIterable(numberList -&gt; numberList ) 更容易阅读和理解。

区别似乎是顺序(RxJava2):

  • Observable.fromIterable: 将一个 Iterable 序列转换为一个 ObservableSource,它会发出序列中的项目。
  • Observable.flatMapIterable:返回一个 Observable,它将源 ObservableSource 发出的每个项目与由选择器生成的项目对应的 Iterable 中的值合并。

使用方法引用如下:

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

【讨论】:

【解决方案3】:

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

  1. 该函数获取每个发射的项目(Iterable&lt;T&gt;)并将其重新发射为Observable&lt;T&gt;
  2. flatMap 将这些发出的 Observable&lt;T&gt; 对象中的每一个都合并为一个 Observable&lt;T&gt;

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

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

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

【讨论】:

    【解决方案4】:

    在 Kotlin 中使用 flattenAsFlowable:

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

    【讨论】:

      【解决方案5】:

      对于科特林

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

      【讨论】:

        猜你喜欢
        • 2017-01-05
        • 1970-01-01
        • 1970-01-01
        • 2017-11-05
        • 1970-01-01
        • 2015-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多