现在玩RxJava并偶然发现以下问题:
我有两个不同的流:
所以基本上我有项目流,我希望所有这些项目都与第二个流中的单个项目相结合:
---- ---- A1 A2 A3 ---- ---- ---- A4 A5 ---- | --------------->
------------- b1-- | ------------------------------ ----->
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
------------ A1B1-A2B1-A3B1-A4B1-a5b1 -------->
它看起来与combileLatest
运算符非常相似,但combineLatest将忽略第一个流中的所有项目,除了最接近第二个流中的项目。这意味着我不会收到a1b1
- 发出的第一个结果项目将是a2b1
。
我还查看了delay
运算符,但它不允许我指定close
流,就像使用buffer
运算符一样
是否有任何花哨的操作员可以解决上述问题?
答案 0 :(得分:2)
有几种方法可以实现这一目标:
1)flatMap
超过b
,如果您不需要提前a
b.flatMap(bv -> a.map(av -> together(av, bv)));
2)当然,您可以cache
,但它会在整个广告播放期间保留您的a
。
3)使用groupBy有点非常规,因为它的GroupedObservable缓存值直到单个订阅者到达,重放缓存的值并继续作为常规直接可观察(让所有先前的缓存值继续)。
Observable<Long> source = Observable.timer(1000, 1000, TimeUnit.MILLISECONDS)
.doOnNext(v -> System.out.println("Tick"))
.take(10);
Observable<String> other = Observable.just("-b").delay(5000, TimeUnit.MILLISECONDS)
.doOnNext(v -> System.out.println("Tack"))
;
source.groupBy(v -> 1)
.flatMap(g ->
other.flatMap(b -> g.map(a -> a + b))
).toBlocking().forEach(System.out::println);
它的工作原理如下:
GroupedObservable
。g
到达时,我们开始观察&#39;另一个可观察的。a + b
s。我添加了doOnNexts,因此您可以在other
触发&#34; Tack&#34;之前看到源是真正有效的。
答案 1 :(得分:1)
AFAIK,没有内置的操作员来实现您所描述的行为。您始终可以实现自定义运算符或在现有运算符之上构建它。我认为第二个选项更容易实现,这是代码:
public static <L, R, T> Observable<T> zipper(final Observable<? extends L> left, final Observable<? extends R> right, final Func2<? super L, ? super R, ? extends T> function) {
return Observable.defer(new Func0<Observable<T>>() {
@Override
public Observable<T> call() {
final SerialSubscription subscription = new SerialSubscription();
final ConnectableObservable<? extends R> cached = right.replay();
return left.flatMap(new Func1<L, Observable<T>>() {
@Override
public Observable<T> call(final L valueLeft) {
return cached.map(new Func1<R, T>() {
@Override
public T call(final R valueRight) {
return function.call(valueLeft, valueRight);
}
});
}
}).doOnSubscribe(new Action0() {
@Override
public void call() {
subscription.set(cached.connect());
}
}).doOnUnsubscribe(new Action0() {
@Override
public void call() {
subscription.unsubscribe();
}
});
}
});
}
如果您对代码有任何疑问,我可以详细解释。
<强>更新强>
关于如何解决我的解决方案与以下方案的不同之处:
left.flatMap(valueLeft -> right.map(valueRight -> together(valueLeft, valueRight)));
left
和right
可观察对象并行执行。 right
可观察的left
不必等待right
个人发出第一个项目。缓存 - 我的解决方案只为b1
观察者订阅一次并缓存其结果。这就是为什么aXXX
对于所有right
项始终相同的原因。每次left
发出项目时,akarnokd提供的解决方案都会订阅b1
观察点。这意味着:
无法保证b
不会更改其值。例如,对于以下可观察对象,您将为每个a
获得不同的final Observable<Double> right = Observable.defer(new Func0<Observable<Double>>() {
@Override
public Observable<Double> call() {
return Observable.just(Math.random());
}
});
。
right
如果left
observable是一项耗时的操作(例如网络呼叫),则每次Hashtable props = new Hashtable();
props.put(Context.SECURITY_PRINCIPAL, "cn=Bob,cn=Users,dc=myCompany,dc=com");
props.put(Context.SECURITY_CREDENTIALS, "Password1");
props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
props.put(Context.PROVIDER_URL, url);
InitialLdapContext context = new InitialLdapContext(props, null);
observable发出新项目时,您都必须等待其完成。