繁体   English   中英

将Observable of List转换为Observable列表并在RxJava中合并

[英]Convert Observable of List to List of Observables and merge in RxJava

我正在通过创建黑客新闻阅读器应用程序来学习Java。

我想要做的是:

  1. /topstories发送请求,返回Observable<List<int>> ,在请求完成时发出。
  2. 将每个storyIdObservable<Story>
  3. 当所有请求完成时,将Observable合并为一个实体,该实体将发出List<Story>

而代码:

  private Observable<Story> getStoryById(int articleId) {
    BehaviorSubject<Story> subject = BehaviorSubject.create();
    // calls subject.onNext on success
    JsonObjectRequest request = createStoryRequest(articleId, subject);
    requestQueue.add(request);
    return subject;
  }

  public Observable<ArrayList<Story>> getTopStories(int amount) {
    Observable<ArrayList<Integer>> topStoryIds = (storyIdCache == null)
      ? fetchTopIds()
      : Observable.just(storyIdCache);

    return topStoryIds
      .flatMap(id -> getStoryById(id))
      // some magic here
  }

那我们就像这样使用:

getTopStories(20)
  .subscribe(stories -> ...)

你可以试试这样的东西

Observable<List<Integers>> ids = getIdsObservable();
Single<List<Story>> listSingle =
            ids.flatMapIterable(ids -> ids)
            .flatMap(id -> getStoryById(id)).toList();

然后,您可以订阅该Single以获取List<Story>

请看看我的解决方案。 我更改了你的接口,为getStoryById()返回一个Single,因为它应该只返回一个值。 之后,我为每个Story创建了一个Single请求,并使用Single.zip订阅了所有这些请求。 当所有单打结束时,Zip将执行给定的lambda。 缺点是,所有请求将立即被触发。 如果你不想这样,我会更新我的帖子。 请考虑@elmorabea解决方案还将订阅前128个元素(BUFFER_SIZE = Math.max(1,Integer.getInteger(“rx2.buffer-size”,128));),以及下一个元素饰面。

@Test
  void name() {
    Api api = mock(Api.class);

    when(api.getTopStories()).thenReturn(Flowable.just(Arrays.asList(new Story(1), new Story(2))));
    when(api.getStoryById(eq(1))).thenReturn(Single.just(new Story(888)));
    when(api.getStoryById(eq(2))).thenReturn(Single.just(new Story(888)));

    Flowable<List<Story>> listFlowable =
        api.getTopStories()
            .flatMapSingle(
                stories -> {
                  List<Single<Story>> collect =
                      stories
                          .stream()
                          .map(story -> api.getStoryById(story.id))
                          .collect(Collectors.toList());

                  // possibly not the best idea to subscribe to all singles at the same time
                  Single<List<Story>> zip =
                      Single.zip(
                          collect,
                          objects -> {
                            return Arrays.stream(objects)
                                .map(o -> (Story) o)
                                .collect(Collectors.toList());
                          });

                  return zip;
                });

    TestSubscriber<List<Story>> listTestSubscriber =
        listFlowable.test().assertComplete().assertValueCount(1).assertNoErrors();

    List<List<Story>> values = listTestSubscriber.values();

    List<Story> stories = values.get(0);

    assertThat(stories.size()).isEqualTo(2);
    assertThat(stories.get(0).id).isEqualTo(888);
    assertThat(stories.get(1).id).isEqualTo(888);
  }

  interface Api {
    Flowable<List<Story>> getTopStories();

    Single<Story> getStoryById(int id);
  }

  static class Story {
    private final int id;

    Story(int id) {
      this.id = id;
    }
  }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM