如何控制RxJava 2中的订阅计数?

时间:2017-06-16 17:15:39

标签: java rx-java rx-java2

我有一个长时间运行的任务(比如一个Observable<Integer>)我想在我的应用程序中尽可能少地触发。我有多个&#34;观点&#34;处理以各种方式发送的事件的任务。我的整个应用程序中只有一个subscribe

如何确保长时间运行的任务仅针对每个订阅触发一次,并且仅在订阅需要时触发?

为了使事情更具体,这是一个单元测试:

@Test
public void testSubscriptionCount() {

    final Counter counter = new Counter();

    // Some long running tasks that should be triggered once per subscribe
    final Observable<Integer> a = Observable.just(1, 2, 3, 4, 5)
        .doOnSubscribe(subscription -> {
            counter.increment();
        });

    // Some "view" on the long running task
    final Observable<Integer> b = a.filter(x -> x % 2 == 0);

    // Another "view" on the long running task
    final Observable<Integer> c = a.filter(x -> x % 2 == 1);

    // A view on the views
    final Observable<Integer> d = Observable.zip(b, c, (x, y) -> x + y);

    d.toList().blockingGet();

    assertEquals(1, counter.count); // Fails, counter.count == 2
}

我希望a只能在订阅其中一个视图(bcd)时触发,而且每个订阅只能触发一次。

在上面的代码中,订阅发生两次(我假设d触发bc,它们都独立触发a

添加.share()并不能解决问题(尽管我认为这是正确的):

    // Some long running tasks that should be triggered once per subscribe
    final Observable<Integer> a = Observable.just(1, 2, 3, 4, 5)
        .doOnSubscribe(subscription -> counter.increment())
        .share();
  

java.lang.AssertionError:

     

预计:1

     

实际:2

1 个答案:

答案 0 :(得分:0)

如果您的目标是在观察者并行订阅时阻止多次执行,Observable<Integer> shared = source.share(); // In thread 1: shared.subscribe(...); // In thread 2: shared.subscribe(...); 就是您所寻找的:

.share()

只要源observable在第二次订阅发生时尚未完成,它将获得与第一次订阅相同的结果,并且不会强制执行源可观察的另一次。

RxJava文档有更详细的解释,但它基本上是一个包含一些引用计数的包装器,并且只在必要时订阅源observable以避免并发执行。

还要记住,时间安排将在实际传递价值的过程中起到重要作用。我不相信.buffer()将对元素进行任何特定的缓冲,因此如果元素在第二个订阅之前传递,则第二个订阅将不会获得这些元素。您必须使用HEAD或其他一些方法来保留后期订阅者的结果。