变换observable以使值之间具有最小延迟

时间:2016-05-25 19:25:15

标签: java rx-java observable

我正在寻找this question的良好解决方案,但在RxJava中实现。问题也是五年多了,所以我想知道 - 是否有更好的方法来实现这一输出?

  

我想要实现的是缓冲某些传入的事件   IObservable(它们突然爆发)并进一步发布,但只有一个   一个,偶数间隔。像这样:

-oo-ooo-oo------------------oooo-oo-o-------------->

-o--o--o--o--o--o--o--------o--o--o--o--o--o--o---->

对我来说最大的要求是没有观察到丢失,事件的顺序保持不变。

1 个答案:

答案 0 :(得分:6)

此特定模式需要记住最后一个事件的安排时间,因此如果下一个事件发生在一个时间段之后,它可以立即发出并开始新的定期发射。也许更简单有效的方法是编写自定义运算符:

import java.util.concurrent.TimeUnit;

import rx.*;
import rx.Observable.Operator;
import rx.schedulers.Schedulers;

public class SpanOut<T> implements Operator<T, T> {
    final long time;

    final TimeUnit unit;

    final Scheduler scheduler;

    public SpanOut(long time, TimeUnit unit, Scheduler scheduler) {
        this.time = time;
        this.unit = unit;
        this.scheduler = scheduler;
    }

    @Override
    public Subscriber<? super T> call(Subscriber<? super T> t) {
        Scheduler.Worker w = scheduler.createWorker();

        SpanSubscriber<T> parent = new SpanSubscriber<>(t, unit.toMillis(time), w);

        t.add(w);
        t.add(parent);

        return parent;
    }

    static final class SpanSubscriber<T> extends Subscriber<T> {
        final Subscriber<? super T> actual;

        final long spanMillis;

        final Scheduler.Worker worker;

        long lastTime;

        public SpanSubscriber(Subscriber<? super T> actual, 
                long spanMillis, Scheduler.Worker worker) {
            this.actual = actual;
            this.spanMillis = spanMillis;
            this.worker = worker;
        }

        @Override
        public void onNext(T t) {
            long now = worker.now();
            if (now >= lastTime + spanMillis) {
                lastTime = now + spanMillis;
                worker.schedule(() -> {
                    actual.onNext(t);
                });
            } else {
                long next = lastTime - now;
                lastTime += spanMillis;
                worker.schedule(() -> {
                    actual.onNext(t);
                }, next, TimeUnit.MILLISECONDS);
            }
        }

        @Override
        public void onError(Throwable e) {
            worker.schedule(() -> {
                actual.onError(e);
                unsubscribe();
            });
        }

        @Override
        public void onCompleted() {
            long next = lastTime - worker.now();
            worker.schedule(() -> {
                actual.onCompleted();
                unsubscribe();
            }, next, TimeUnit.MILLISECONDS);
        }

        @Override
        public void setProducer(Producer p) {
            actual.setProducer(p);
        }
    }

    public static void main(String[] args) {
        Observable.range(1, 5)
        .concatWith(Observable.just(6).delay(6500, TimeUnit.MILLISECONDS))
        .concatWith(Observable.range(7, 4))
        .lift(new SpanOut<>(1, TimeUnit.SECONDS, Schedulers.computation()))
        .timeInterval()
        .toBlocking()
        .subscribe(System.out::println);
    }
}