Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rx java RxJava中的类队列主题_Rx Java - Fatal编程技术网

Rx java RxJava中的类队列主题

Rx java RxJava中的类队列主题,rx-java,Rx Java,我正在寻找一个可以: 如果没有订阅服务器,则可以接收项目并将其保存在队列或缓冲区中 一旦我们有了订阅者,所有的物品都会被消耗掉,再也不会发出 我可以订阅/取消订阅主题 BehaviorSubject几乎可以完成这项工作,但它保留了最后观察到的项 更新 根据公认的答案,我为单个观察项目制定了类似的解决方案。还添加了取消订阅部分,以避免内存泄漏 class LastEventObservable private constructor( private val onSubscribe

我正在寻找一个可以:

  • 如果没有订阅服务器,则可以接收项目并将其保存在队列或缓冲区中
  • 一旦我们有了订阅者,所有的物品都会被消耗掉,再也不会发出
  • 我可以订阅/取消订阅主题
  • BehaviorSubject
    几乎可以完成这项工作,但它保留了最后观察到的项

    更新

    根据公认的答案,我为单个观察项目制定了类似的解决方案。还添加了取消订阅部分,以避免内存泄漏

    class LastEventObservable private constructor(
            private val onSubscribe: OnSubscribe<Any>,
            private val state: State
    ) : Observable<Any>(onSubscribe) {
    
        fun emit(value: Any) {
            if (state.subscriber.hasObservers()) {
                state.subscriber.onNext(value)
            } else {
                state.lastItem = value
            }
        }
    
        companion object {
            fun create(): LastEventObservable {
                val state = State()
    
                val onSubscribe = OnSubscribe<Any> { subscriber ->
                    just(state.lastItem)
                            .filter { it != null }
                            .doOnNext { subscriber.onNext(it) }
                            .doOnCompleted { state.lastItem = null }
                            .subscribe()
    
                    val subscription = state.subscriber.subscribe(subscriber)
    
                    subscriber.add(Subscriptions.create { subscription.unsubscribe() })
                }
    
                return LastEventObservable(onSubscribe, state)
            }
        }
    
        private class State {
            var lastItem: Any? = null
            val subscriber = PublishSubject.create<Any>()
        }
    }
    
    class LastEventObservable私有构造函数(
    私人val onSubscribe:onSubscribe,
    私有val状态:状态
    ):可观察(未订阅){
    乐趣释放(值:任意){
    if(state.subscriber.hasObservators()){
    state.subscriber.onNext(值)
    }否则{
    state.lastItem=值
    }
    }
    伴星{
    fun create():LastEventObservable{
    val state=state()
    val onSubscribe=onSubscribe{subscriber->
    just(state.lastItem)
    .filter{it!=null}
    .doOnNext{subscriber.onNext(it)}
    .doOnCompleted{state.lastItem=null}
    .subscribe()
    val subscription=state.subscriber.subscribe(订户)
    subscriber.add(Subscriptions.create{subscription.unsubscripte()})
    }
    返回LastEventObservable(onSubscribe,state)
    }
    }
    私有阶级国家{
    var lastItem:有吗?=null
    val subscriber=PublishSubject.create()
    }
    }
    
    我创建了一个定制的Observable,用于包装发布主题,并在没有附加订阅者的情况下处理发射缓存,从而达到了预期的效果。看看吧

    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);
            }
        }
    }
    
    公共类ExampleUnitTest{
    @试验
    public void testSample()引发异常{
    MyCustomObservable MyCustomObservable=新的MyCustomObservable();
    myCustomObservable.emit(“1”);
    myCustomObservable.emit(“2”);
    myCustomObservable.emit(“3”);
    订阅订阅=myCustomObservable.subscribe(System.out::println);
    myCustomObservable.emit(“4”);
    myCustomObservable.emit(“5”);
    订阅。取消订阅();
    myCustomObservable.emit(“6”);
    myCustomObservable.emit(“7”);
    myCustomObservable.emit(“8”);
    myCustomObservable.subscribe(System.out::println);
    }
    }
    类MyCustomObservable扩展了Observable{
    私有静态PublishSubject PublishSubject=PublishSubject.create();
    私有静态列表valuesCache=newarraylist();
    受保护的MyCustomObservable(){
    超级(订户->{
    可观察。来自(valuesCache)
    .doOnNext(订户::onNext)
    .doOnCompleted(valuesCache::clear)
    .subscribe();
    publishSubject.订阅(订户);
    });
    }
    公共void发出(字符串值){
    if(publishSubject.hasObservators()){
    publishSubject.onNext(值);
    }否则{
    添加(值);
    }
    }
    }
    
    希望能有帮助


    诚挚的问候。

    < P>如果只想等待一个用户,请使用<代码> UnaseTase< /C>。但是注意,如果在中间不订阅,所有后续的队列项都将丢失。

    编辑:

    一旦我们有了a订阅者,所有的物品都会被消耗掉,再也不会发出


    对于多个订阅者,请使用
    ReplaySubject

    我遇到了类似的问题,我的要求是:

    • 应支持在没有观察员订阅时重播值
    • 一次只允许订阅一个观察者
    • 当第一个观察者被释放时,应该允许另一个观察者订阅
    我已经将其实现为,但主题的实现类似:

    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);
            }
        }
    }
    
    公共最终类缓存中继扩展中继{
    私有最终ConcurrentLinkedQueue队列=新ConcurrentLinkedQueue();
    private final PublishRelay relay=PublishRelay.create();
    专用缓存中继(){
    }
    公共静态缓存中继创建(){
    返回新的CacheRelay();
    }
    @凌驾
    公共无效接受(T值){
    if(relay.hasObservators()){
    继电器。接受(值);
    }否则{
    添加(值);
    }
    }
    @凌驾
    公共布尔hasObservators(){
    返回继电器;
    }
    @凌驾
    
    受保护的void subscribeActual(observer)应该可能有多个订阅者。@MartynasJurkus您可以将
    UnicastSubject
    .publish().autoConnect()
    一起使用,但您不能在第一次取消订阅和第二次订阅之间“缓存”项目。但有一个库具有
    UnicastWorkerSubject
    ,允许这样做(但仍同时有一个订阅服务器)或允许多个订阅服务器的
    DispatchWorkSubject
    。很遗憾,您无法指定缓冲区大小,因为在
    create()中
    方法您可以传递
    capacityHint
    ,它不是指定的容量大小。这只是一个提示,因为
    SpscLinkedArrayQueue
    SPCLinkedArrayQueue
    的实现,您看到我的答案了吗?请澄清您所说的“一旦我们有了订阅者,所有项目都将被消耗,并且永远不会再次发出”是什么意思-如果您有类似于:yourSource.take(1).subscribe()的内容,那么这是否应该删除源中的所有项目?不,这应该只消耗该项目。工作起来很有魅力。不过我不太喜欢这些静态变量:)我也是@MartynasJurkus。我们如何改进这个解决方案?请看我更新的问题。虽然我的代码是Kotlin。太棒了!我喜欢Koltin。你的最终解决方案比我最初的解决方案漂亮得多。我创建了一个库,灵感来自这篇文章:如何将工作移动到后台线程?我所做的所有操作