如何创建一个Flowable,它在最后一个订阅者取消订阅后立即完成

时间:2019-02-22 11:06:53

标签: java reactive-programming rx-java2

在某些情况下,我需要建立一个由多个元素组成的反应性流,可以用两种不同的方式来完成。

我的链条看起来像这样:

在链的顶部,我有多个Flowable生产者,每个生产者定期轮询不同的远程资源并在获得新结果时发出消息。

每个生产者都有一个中间订户,可以进一步转换消息。

依次,所有这些中间订阅者都具有相同的根订阅者,该根订阅者将来自所有人的转换后的事件合并为一个Flowable

我想要的是能够取消根订阅者的任何订阅,并让取消订阅事件基本上导致取消订阅(这是一个单词吗?)。

换句话说,如果没有人在听,我希望我的轮询过程停止。如果我需要重新启动轮询,只需重建一个新链。

是否有任何RxJava运算符允许我在生产者和订阅者之间创建这种关系?如果没有,那么最简单的方法是什么?

我现在有一种解决方案,但是感觉不是一个很好的解决方案,并且链中每个元素都需要大量样板代码。看起来像这样:

private class AutoUnsubscribing {
    private final AtomicReference<Subscription> upstreamSubscription = new AtomicReference<>(null);
    private final PublishProcessor<LedgerEvent> publisher = PublishProcessor.create();

    public Flowable<LedgerEvent> getFlowable(Flowable<LedgerEvent> upstream) {
        upstream.subscribe(new Subscriber<LedgerEvent>() {
            @Override
            public void onSubscribe(Subscription s) {
                upstreamSubscription.set(s);
            }

            @Override
            public void onNext(LedgerEvent ledgerEvent) {
                publisher.onNext(ledgerEvent);
            }

            @Override
            public void onError(Throwable t) {
                publisher.onError(t);
            }

            @Override
            public void onComplete() {
                publisher.onComplete();
            }
        });

        return publisher.doOnCancel(() -> {
            if (!publisher.hasSubscribers()) {
                // no more subscribers. unsubscribe from upstream and complete this stream
                upstreamSubscription.get().cancel();
                upstreamSubscription.set(null);
                publisher.onComplete();
            }
        });
    }
}

但是必须有比这更好的解决方案。

1 个答案:

答案 0 :(得分:0)

现在,我已经在RxJava方面获得了更多的经验,现在可以为我的问题提出答案。基本上,我们拥有的链条如下:

+----------+      +-------------+      +----------+
| consumer |←-----| transformer |←-----| producer |
+----------+      +-------------+      +----------+

真正需要的是一种使transformer可取消的方法,以使取消该预订时取消对producer的订阅(因此producer可以进行一些清理)在终止自身之前),并且AND transformer完成自身(以便consumer意识到这一点)。

我能找到的最佳解决方案是像这样实现detachable运算符:

public static <T> FlowableTransformer<T, T> detachable(
            Consumer<Disposable> disposableConsumer) {
    PublishProcessor<Object> stopper = PublishProcessor.create();
    Disposable disposable = new Disposable() {
        private AtomicBoolean disposed = new AtomicBoolean(false);

        @Override
        public void dispose() {
            if (disposed.compareAndSet(false, true)) {
                stopper.onNext(new Object());
            }
        }

        @Override
        public boolean isDisposed() {
            return disposed.get();
        }
    };

    return upstream -> upstream.takeUntil(stopper)
            .doOnSubscribe(s -> disposableConsumer.accept(disposable));

}

然后可以使用哪种方式:

AtomicReference<Disposable> transformerDisposable = new AtomicReference<>();

producer
    .compose(detachable(transformerDisposable::set))
    .subscriber(consumer)

然后可以使用{p>随意取消transfomer

transformerDisposable.dispose()

这确实会导致producer调用自己的onUnsubscribe,并且consumer会收到onComplete通知。