Queue like Subject in RxJava

前端 未结 3 1326
梦毁少年i
梦毁少年i 2020-12-29 06:06

I\'m looking for a Subject (or something similar) that can:

  1. Could receive items and hold them in a queue or buffer if there are no subscribers
  2. Once we
相关标签:
3条回答
  • 2020-12-29 06:40

    If you only want to wait for a single subscriber, use UnicastSubject but note that if you unsubscribe in the middle, all subsequent queued items will be lost.

    Edit:

    Once we have a subscriber all items are consumed and never emitted again

    For multiple subscribers, use ReplaySubject.

    0 讨论(0)
  • 2020-12-29 06:53

    I achieve the expected result creating a customized Observable that wraps a publish subject and handles emission cache if there's no subscribers attached. Check it out.

    public class ExampleUnitTest {
        @Test
        public void testSample() throws Exception {
            MyCustomObservable myCustomObservable = new MyCustomObservable();
    
            myCustomObservable.emit("1");
            myCustomObservable.emit("2");
            myCustomObservable.emit("3");
    
            Subscription subscription = myCustomObservable.subscribe(System.out::println);
    
            myCustomObservable.emit("4");
            myCustomObservable.emit("5");
    
            subscription.unsubscribe();
    
            myCustomObservable.emit("6");
            myCustomObservable.emit("7");
            myCustomObservable.emit("8");
    
            myCustomObservable.subscribe(System.out::println);
        }
    }
    
    class MyCustomObservable extends Observable<String> {
        private static PublishSubject<String> publishSubject = PublishSubject.create();
        private static List<String> valuesCache = new ArrayList<>();
    
        protected MyCustomObservable() {
            super(subscriber -> {
                Observable.from(valuesCache)
                        .doOnNext(subscriber::onNext)
                        .doOnCompleted(valuesCache::clear)
                        .subscribe();
    
                publishSubject.subscribe(subscriber);
            });
        }
    
        public void emit(String value) {
            if (publishSubject.hasObservers()) {
                publishSubject.onNext(value);
            } else {
                valuesCache.add(value);
            }
        }
    }
    

    Hope that it helps!

    Best Regards.

    0 讨论(0)
  • 2020-12-29 06:54

    I had similar problem, my requirements were:

    • Should support replay of values when no Observer subscribed
    • Should allow only one Observer subscribed at a time
    • Should allow another Observer to subscribe when first Observer is disposed

    I've implemented it as RxRelay but the implementation for Subject would be similar:

    public final class CacheRelay<T> extends Relay<T> {
    
        private final ConcurrentLinkedQueue<T> queue = new ConcurrentLinkedQueue<>();
        private final PublishRelay<T> relay = PublishRelay.create();
    
        private CacheRelay() {
        }
    
        public static <T> CacheRelay<T> create() {
            return new CacheRelay<>();
        }
    
        @Override
        public void accept(T value) {
            if (relay.hasObservers()) {
                relay.accept(value);
            } else {
                queue.add(value);
            }
        }
    
        @Override
        public boolean hasObservers() {
            return relay.hasObservers();
        }
    
        @Override
        protected void subscribeActual(Observer<? super T> observer) {
            if (hasObservers()) {
                EmptyDisposable.error(new IllegalStateException("Only a single observer at a time allowed."), observer);
            } else {
                for (T element; (element = queue.poll()) != null; ) {
                    observer.onNext(element);
                }
                relay.subscribeActual(observer);
            }
        }
    }
    

    Look at this Gist for more

    0 讨论(0)
提交回复
热议问题