Rxjava2 debounce

349 阅读2分钟

debounce操作符可以一定的节奏发射数据,防止生产者生产速度太快,导致下流忙不过来,典型可以用在搜索中,每次搜索框字符发生变化,就会请求数据,但是我们可以限制一定时间内只能请求一次,就可以用到debounce,该操作符会丢弃数据。

 Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NotNull ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                Thread.sleep(1000);
                emitter.onNext(2);
                Thread.sleep(1000);
                emitter.onNext(3);
                emitter.onComplete();
            }
        }).debounce(4000, TimeUnit.MILLISECONDS)
                .subscribe(new Observer<Integer>() {
                    @Override
                    public void onSubscribe(@NotNull Disposable d) {
                        System.out.println("onSubscribe ");
                    }

                    @Override
                    public void onNext(@NotNull Integer integer) {
                        System.out.println("onNext " + integer);
                    }

                    @Override
                    public void onError(@NotNull Throwable e) {
                        System.out.println("onError " + e.getMessage());
                    }

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

输出

onSubscribe 
onNext 3
onComplete

我们用debounce操作符限制4s内只能发射一次,当发射1后,sleep 1s,醒来后发射2,继续sleep 1s,这时已经消耗大概2s了,还没到4s,发射3,等到时间到达4s后将数据3发射出来。

看看源码是如何实现的

   public final Observable<T> debounce(long timeout, TimeUnit unit) {
        return debounce(timeout, unit, Schedulers.computation());
    }
    
     public final Observable<T> debounce(long timeout, TimeUnit unit, Scheduler scheduler) {
        ...
        return RxJavaPlugins.onAssembly(new ObservableDebounceTimed<T>(this, timeout, unit, scheduler));
    }
    
public final class ObservableDebounceTimed<T> extends AbstractObservableWithUpstream<T, T> {
    final long timeout;
    final TimeUnit unit;
    final Scheduler scheduler;

    public ObservableDebounceTimed(ObservableSource<T> source, long timeout, TimeUnit unit, Scheduler scheduler) {
        super(source);
        this.timeout = timeout;
        this.unit = unit;
        this.scheduler = scheduler;
    }

    @Override
    public void subscribeActual(Observer<? super T> t) {
        source.subscribe(new DebounceTimedObserver<T>(
                new SerializedObserver<T>(t),
                timeout, unit, scheduler.createWorker()));
    }
    
    ...
   }

主要还是DebounceTimedObserver对象,这里的核心还是实现worker延时执行任务,用index 标识每一个DebounceEmitter,假如这里数据身生产者生产很快,上一次的DebounceEmitter还没到执行,就需要被 d.dispose();结束掉了,那么这个数据就被丢弃了,最后一个数据,例子中就是数据3,就是延时后执行的效果。

        public void onNext(T t) {
            if (done) {
                return;
            }
            long idx = index + 1;
            index = idx;

            Disposable d = timer;
            if (d != null) {
                d.dispose();
            }

            DebounceEmitter<T> de = new DebounceEmitter<T>(t, idx, this);
            timer = de;
            d = worker.schedule(de, timeout, unit);
            de.setResource(d);
        }
        
        void emit(long idx, T t, DebounceEmitter<T> emitter) {
            if (idx == index) {
                downstream.onNext(t);
                emitter.dispose();
            }
        }        
        

就是说debounce操作符就是延时执行,第一条数据也是延时后发射,而不是立即发射的,该操作符还会丢弃数据。