我会尽量保持这个简单。
我有两个返回observables的API端点httpA
和httpB
:
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
为了将其置于上下文中,我正在尝试实现类似聊天的应用程序。
我的示例中的对象A
为Conversations
,对象B
为User Profile
s(用户信息)。
尝试获取已登录用户的最近会话列表时:
我首先从服务器(Conversations
)带来httpA
,这些用户具有用户ID但不是实际的User Info
名称/详细信息。
要获得User Info
我必须再次访问服务器,传递我感兴趣的所有用户ID(在上面的示例中为httpB
)。
所以“非常非常长”可以是0,100,300次对话。我不认为这会成为一个问题,因为toList()
是一个阻塞运算符。但我对Rx很新,所以我不太确定。
答案 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";
}));