我正在寻找this question的良好解决方案,但在RxJava中实现。问题也是五年多了,所以我想知道 - 是否有更好的方法来实现这一输出?
我想要实现的是缓冲某些传入的事件 IObservable(它们突然爆发)并进一步发布,但只有一个 一个,偶数间隔。像这样:
-oo-ooo-oo------------------oooo-oo-o--------------> -o--o--o--o--o--o--o--------o--o--o--o--o--o--o---->
对我来说最大的要求是没有观察到丢失,事件的顺序保持不变。
答案 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);
}
}