OnSubscribe.call方法调用了两次

时间:2016-01-04 01:48:53

标签: rx-java observable

背景 我想在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");
}

2 个答案:

答案 0 :(得分:2)

这可能不是那么相关,因为你已经在你的情况下解决了问题,但是使用原始OnSubscribe创建observable通常是容易出错的。更好的方法是使用现有的辅助类之一:SyncOnSubscribe / AsyncOnSubscribe(自RxJava 1.0.15起)或AbstractOnSubscribe(最多RxJava v1.1.0)。它们为您提供了一个现成的框架来管理可观察的状态和背压,让您(主要)处理您自己的逻辑。

答案 1 :(得分:0)

Dispose可能会被愚弄订阅一个闩锁,因此你的两个订阅。

但我认为您使用toBlocking是正确的,并且应该将该部分作为解决方案。

问题是你的第二次订阅,是通过调用toBlocking().forEach()进行的。是否真的需要subscribe?如果只是记录而不是实际修改数据流,则可以使用subscribedoOnNextdoOnError代替。

如果您的用例比您的问题中反映的要复杂得多,并且您确实需要等待两个“并行”异步处理,那么您可能需要加入并等待doOnCompleted(或类似) )...请记住,如果你想要并行,RxJava在这方面是不可知的,你需要使用CountDownLatchSchedulers / subscribeOn来驱动它。