背景 我想在OnSubscribe的调用方法中调用一个Web服务。还有一个自定义订阅者类,它也是此Observable的订阅者。 (以下代码是相似的近似值)
问题: 看到OnSubscribe.call方法被调用两次。
Observable.create(...)',subscribe(...)和最终转换observable toBlocking之间的关系对我来说并不清楚。似乎下面的行添加了行为,并以某种方式再次调用OnSubscribe.call。我假设最终需要调用toBlocking调用 - 就在结果由webserver返回之前(servlet / controller本质上是非Rx)。
observable.toBlocking().forEach(i-> System.out.println(i));
完整的代码
public static void main(String args[]){
Observable<Integer> observable = Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> observer) {
System.out.println("In OnSubscribe Create: "+observer.isUnsubscribed());
try {
if (!observer.isUnsubscribed()) {
for (int i = 1; i < 5; i++) {
observer.onNext(i);
}
observer.onCompleted();
}
} catch (Exception e) {
observer.onError(e);
}
}
});
observable.subscribe(new Subscriber<Integer>() {
@Override
public void onNext(Integer item) {
System.out.println("Next: " + item);
}
@Override
public void onError(Throwable error) {
System.err.println("Error: " + error.getMessage());
}
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
});
observable.toBlocking().forEach(i-> System.out.println(i));
}
输出
In OnSubscribe Create: false
Next: 1
Next: 2
Next: 3
Next: 4
Sequence complete.
In OnSubscribe Create: false
For Each Printing 1
For Each Printing 2
For Each Printing 3
For Each Printing 4
回答自己的问题: 我通过forEach处理结果的方式是错误的。这本身就是订阅者,因此最终再次调用call方法。 正确地做我正在做的事情是通过CountDownLatch。
这也澄清了我的另一个疑问 - 在我们最终等待工作在控制器/ servlet中返回响应之前完成工作的上下文中意味着使用具有超时的锁存器。
以下代码。
public static void main(String args[]) throws Exception {
CountDownLatch latch = new CountDownLatch(4);
Observable<Integer> observable = Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> observer) {
System.out.println("In OnSubscribe Create: "+observer.isUnsubscribed());
try {
if (!observer.isUnsubscribed()) {
for (int i = 1; i < 5; i++) {
observer.onNext(i);
latch.countDown();
}
observer.onCompleted();
}
} catch (Exception e) {
observer.onError(e);
}
}
});
observable.subscribe(new Subscriber<Integer>() {
@Override
public void onNext(Integer item) {
System.out.println("Next: " + item);
}
@Override
public void onError(Throwable error) {
System.err.println("Error: " + error.getMessage());
}
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
});
latch.await();
System.out.println(" Wait for Latch Over");
}
答案 0 :(得分:2)
这可能不是那么相关,因为你已经在你的情况下解决了问题,但是使用原始OnSubscribe创建observable通常是容易出错的。更好的方法是使用现有的辅助类之一:SyncOnSubscribe / AsyncOnSubscribe(自RxJava 1.0.15起)或AbstractOnSubscribe(最多RxJava v1.1.0)。它们为您提供了一个现成的框架来管理可观察的状态和背压,让您(主要)处理您自己的逻辑。
答案 1 :(得分:0)
Dispose
可能会被愚弄订阅一个闩锁,因此你的两个订阅。
但我认为您使用toBlocking
是正确的,并且应该将该部分作为解决方案。
问题是你的第二次订阅,是通过调用toBlocking().forEach()
进行的。是否真的需要subscribe
?如果只是记录而不是实际修改数据流,则可以使用subscribe
,doOnNext
和doOnError
代替。
如果您的用例比您的问题中反映的要复杂得多,并且您确实需要等待两个“并行”异步处理,那么您可能需要加入并等待doOnCompleted
(或类似) )...请记住,如果你想要并行,RxJava在这方面是不可知的,你需要使用CountDownLatch
,Schedulers
/ subscribeOn
来驱动它。