我正在进入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 + ">");
}
}
似乎很可能有一个更好的解决方案,我无法发现,因为我是框架的新手。有什么想法吗?