后续api调用的相关可观察量

时间:2016-10-25 01:28:08

标签: android rx-java reactive-programming

我会尽量保持这个简单。 我有两个返回observables的API端点httpAhttpB

  • 当我点击端点httpA时,它会返回一个对象流A
  • 同样,当我点击端点httpB时,它会返回一个对象流B

这一切都很简单。我需要将响应压缩在一起,如下所示:

httpA().zipWith(httpB(), new Func2<A, B, SomeCombinationAB> {
   public SomeCombinationAB call(A a, B b) {
      return new SomeCombinationAB(a,b);
   }
});

问题是,HttpB将所有Objects A作为参数。

HttpB(名单A)

所以,我需要以某种方式收集所有 Objects A才能触发HttpB。也就是说,阻止流直到所有A都已交付。 我想我可以使用toList()运算符来完成此操作。

获得As列表后,我必须转换回A流才能压缩两个流:

    List<A> aList;

    httpA.toList().flatMap(new Func1<List<A>, Observable<A>>() {
        @Override
        public Observable<A> call(List<A> listA) {
            aList = listA;
            return Observable.from(listA);
        }
    }).zipWith(httpB(aList), new Func2<A, B, SomeCombinationAB> {
        public SomeCombinationAB call (A a, B b){
            return new SomeCombinationAB(a, b);
        }
    });

这很有效,但肯定感觉不对。我来回转换流。如果A的流非常长,我不确定toList()运算符的行为。 我确信有更好的方法来解决这个问题。

感谢任何帮助 感谢

更新1

为了将其置于上下文中,我正在尝试实现类似聊天的应用程序。  我的示例中的对象AConversations,对象BUser Profile s(用户信息)。

尝试获取已登录用户的最近会话列表时:

  1. 我首先从服务器(Conversations)带来httpA,这些用户具有用户ID但不是实际的User Info名称/详细信息。

  2. 要获得User Info我必须再次访问服务器,传递我感兴趣的所有用户ID(在上面的示例中为httpB)。

  3. 所以“非常非常长”可以是0,100,300次对话。我不认为这会成为一个问题,因为toList()是一个阻塞运算符。但我对Rx很新,所以我不太确定。

2 个答案:

答案 0 :(得分:0)

恕我直言,这里更好的方法是将您现在在zip运算符中的逻辑移动到发出B事件的位置,因为您已经在方法中获得了适当的信息,并将相关结果组合在那里。 ..

你将丢失flatMap运算符并将listA恢复为流...我没有对它进行基准测试,但我会说性能开销不会因为100&#39;而变得非常明显。项目..此外,我不知道你的httpB()方法是怎样的,所以它可能只是为了流可读性而让你的代码变得更糟..

答案 1 :(得分:0)

我想出了同样的解决方案。为了测试我使用RxJava2-RC5。

@Test
public void flatMap21() throws Exception {
        Observable<String> stringObservable = endpointA()
                .toList()
                .flatMapObservable(strings -> endpointB(strings)
                        .zipWith(strings, (integer, s) -> {
                            return "combined";
                        })
                );

        TestObserver<String> test = stringObservable.test();

        test.assertValueCount(3);
}

private Observable<String> endpointA() {
        return Observable.just("1", "2", "3");
}

private Observable<Integer> endpointB(List<String> input) {
        return Observable.just(1, 2, 3);
}

如果网络电话便宜,一种可能的解决方案是将工作批量打包成块。

如果您使用批量大小为5,则observable看起来像这样。

Observable<String> stringObservable = endpointA()
                .buffer(5)
                .flatMap(strings -> endpointB(strings)
                        .zipWith(strings, (integer, s) -> {
                            return "combined";
                        }));