我研究RxJava并尝试理解如何实现非标准的反应性“debouce”逻辑。依赖于消息,如果另一种类型的消息从可观察的消息到达,则新的运算符必须延迟某种消息或跳过它。
Debouce only A-messages or forget about it if another message arrived
请帮助我撰写这个逻辑。
答案 0 :(得分:2)
这需要一个非常重要的运算符组合:
public static <T> ObservableTransformer<T, T> debounceOnly(
Predicate<? super T> condition, long time,
TimeUnit unit, Scheduler scheduler) {
return o -> o.publish(f ->
f.concatMapEager(v -> {
if (condition.test(v)) {
return Observable.just(v).delay(time, unit, scheduler).takeUntil(f);
}
return Observable.just(v);
})
);
}
@Test
public void test() {
PublishSubject<String> subject = PublishSubject.create();
TestScheduler sch = new TestScheduler();
subject
.compose(debounceOnly(v -> v.startsWith("A"),
100, TimeUnit.MILLISECONDS, sch))
.subscribe(System.out::println, Throwable::printStackTrace,
() -> System.out.println("Done"));
subject.onNext("A1");
sch.advanceTimeBy(100, TimeUnit.MILLISECONDS);
subject.onNext("B1");
sch.advanceTimeBy(1, TimeUnit.MILLISECONDS);
subject.onNext("C1");
sch.advanceTimeBy(1, TimeUnit.MILLISECONDS);
subject.onNext("A2");
sch.advanceTimeBy(50, TimeUnit.MILLISECONDS);
subject.onNext("A3");
sch.advanceTimeBy(100, TimeUnit.MILLISECONDS);
subject.onNext("A4");
sch.advanceTimeBy(50, TimeUnit.MILLISECONDS);
subject.onNext("B2");
sch.advanceTimeBy(100, TimeUnit.MILLISECONDS);
subject.onNext("C2");
sch.advanceTimeBy(100, TimeUnit.MILLISECONDS);
subject.onComplete();
}
答案 1 :(得分:0)
RxJava 1.2.10的Kotlin代码:
val sequence = listOf(
Pair(0, "A"), // delay
Pair(3, "B"), // immediately
Pair(4, "C"), // immediately
Pair(5, "A"), // skip by next A
Pair(6, "A"), // delay
Pair(9, "A"), // skip by next B
Pair(10, "B"), // immediately
Pair(11, "C") // immediately
)
val startTime = LocalDateTime.now()
Observable
.from(sequence)
.flatMap { tm ->
Observable.just(tm.second)
.delay(tm.first.toLong(), TimeUnit.SECONDS)
}
.compose { o ->
o.publish { f ->
f.concatMap { v ->
if (v == "A")
Observable.just(v).delay(2, TimeUnit.SECONDS).takeUntil(f)
else
Observable.just(v)
}
}
}
.toBlocking()
.subscribe {
val currentTime = LocalDateTime.now()
val sec = currentTime.toEpochSecond(ZoneOffset.UTC) - startTime.toEpochSecond(ZoneOffset.UTC)
println("$sec - $it")
}