在RxJava2中强化BehaviourSubject的最佳方法是什么?

时间:2017-12-29 12:14:06

标签: java rx-java rx-java2 behaviorsubject

我正在进入RxJava,我正在寻找与多个订阅者共享一些BehaviourSubjects的好方法。每个BehaviourSubject都由一个独特的主题标识,每个主题只应对后端进行一次订阅。

如果BehaviourSubject没有当前订阅者,则应取消订阅后端。

以下代码可以满足我的需求,但MyFakeService类缺乏RxJava所承诺的优雅。

package au.play;

import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.observers.DisposableObserver;
import io.reactivex.subjects.BehaviorSubject;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

public class Demo {
    public static class MyFakeBackEnd {
        private final Observable<Long> FAKE_SOURCE = Observable.interval(30, 10, TimeUnit.MILLISECONDS);

        public Observable<Long> getObservable(String subject) {
            return FAKE_SOURCE;
        }
    }

    public static class MyFakeService {
        private final MyFakeBackEnd myFakeBackEnd = new MyFakeBackEnd();
        private final Map<String, Observable<Long>> subjectMap = new ConcurrentHashMap<>();

        public Observable<Long> getObservable(String subject) {
            return subjectMap.computeIfAbsent(subject, (String key) -> {
                BehaviorSubject<Long> behaviourSubject = BehaviorSubject.createDefault(-1L);

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

                return behaviourSubject
                        .doOnSubscribe(disposable -> {
                            System.out.println("First subscriber for <" + key + ">");
                            final DisposableObserver<Long> disposableObserver = new DisposableObserver<Long>() {
                                @Override
                                public void onNext(Long value) {
                                    behaviourSubject.onNext(value);
                                }

                                @Override
                                public void onError(Throwable e) {
                                    e.printStackTrace();
                                }

                                @Override
                                public void onComplete() {
                                    System.out.println("Why complete?");
                                }
                            };

                            myFakeBackEnd.getObservable(subject).subscribeWith(disposableObserver);
                            atomicDisposable.set(disposableObserver);
                        })
                        .doOnDispose(() -> {
                            System.out.println("Last observer unsubscribed : <" + key + ">");
                            atomicDisposable.get().dispose();
                            behaviourSubject.onNext(-2L);
                        }).share();
            });
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyFakeService service = new MyFakeService();

        System.out.println("C-1 subscription, should trigger 'First subscriber for <firstSubject>' and then start receiving updates. Initial value should be -1");
        Disposable firstDisposable = service.getObservable("firstSubject").subscribe(createConsumer("C-1"));

        Thread.sleep(45);

        System.out.println("C-2 subscription, should not trigger 'First subscriber for <firstSubject>'. Should receive same updates as C-1.");
        Disposable secondDisposable = service.getObservable("firstSubject").subscribe(createConsumer("C-2"));

        System.out.println("C-3 subscription, should trigger 'First subscriber for <secondSubject>' and then start receiving updates. Initial value should be -1");
        Disposable thirdDisposable = service.getObservable("secondSubject").subscribe(createConsumer("C-3"));

        Thread.sleep(45);

        System.out.println("Dispose of C-1 subscription. C-2 should continue getting updates.");
        firstDisposable.dispose();

        Thread.sleep(45);

        System.out.println("Dispose of C-2 subscription. Should trigger 'Last observer unsubscribed : <firstSubject>'.");
        secondDisposable.dispose();

        Thread.sleep(45);

        System.out.println("Dispose of C-3 subscription. Should trigger 'Last observer unsubscribed : <secondSubject>'.");
        thirdDisposable.dispose();

        Thread.sleep(45);

        System.out.println("C-4 subscription, should trigger 'First subscriber for <secondSubject>' and then start receiving updates. Initial value should be -2 as this subject has been subscribed to before.");
        Disposable fourthDisposable = service.getObservable("secondSubject").subscribe(createConsumer("C-3"));

        Thread.sleep(45);

        fourthDisposable.dispose();
    }

    private static Consumer<Long> createConsumer(final String id) {
        return (data) -> System.out.println(id + " : <" + data + ">");
    }
}

似乎很可能有一个更好的解决方案,我无法发现,因为我是框架的新手。有什么想法吗?

0 个答案:

没有答案