RxJava去抖操作符取决于消息

时间:2018-04-14 03:51:30

标签: java rx-java reactive-programming rx-java2

我研究RxJava并尝试理解如何实现非标准的反应性“debouce”逻辑。依赖于消息,如果另一种类型的消息从可观察的消息到达,则新的运算符必须延迟某种消息或跳过它。

Debouce only A-messages or forget about it if another message arrived

请帮助我撰写这个逻辑。

2 个答案:

答案 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")
                    }