簡體   English   中英

在 RxJava 中回滾 Observable?

[英]Rewinding an Observable in RxJava?

我一直在將 RxJava 和反應式編程應用於命令行應用程序。 我一直在發現一些非常棒的設計模式,它們真正簡化了命令行界面的代碼。

然而,有一件事我正在掙扎。 我經常在一系列運算符中發出值,並且我concatMap()Observable.create()來征求用戶對發出的值的輸入。

這很容易,直到我想提供一種方法來返回到之前的發射。 它開始變得非常混亂,盡管我付出了努力,但我知道這並不能 100% 正確地工作。 我希望用戶輸入“BACK”,通過從緩存中請求它來嘗試並倒帶一次發射。 是否有更好的操作員或變壓器來重繞鏈中前一個點的排放並將它們重新發送回去?

public class Test {

    public static void main(String[] args) {

        final Scanner scanner = new Scanner(System.in);
        final List<String> cache = new ArrayList<>();
        final AtomicInteger cursorIndex = new AtomicInteger(-1);


        Observable.just(
                "What is your name?",
                "What is your quest?",
                "What is your favorite color?",
                "What is the capital of Assyria?",
                "What is the velocity of an unladen swallow?"
        )
        .doOnNext(cache::add)
        .concatMap(q -> {
            int cursor = cursorIndex.get();
            if (cursor >= 0 && cursor < cache.size() - 2) {
                return Observable.just(cache.get(cursor));
            } else {
                cursorIndex.incrementAndGet();
                return Observable.just(q);
            }
        })
        .doOnNext(System.out::println)
        .concatMap(q -> Observable.create(s -> {
                    String answer = scanner.nextLine().trim();

                    if (answer.toUpperCase().equals("BACK")) {
                        cursorIndex.decrementAndGet();
                    }
                    s.onNext(answer);
                    s.onCompleted();
                })
        ).filter(s -> !s.equals("BACK"))
         .subscribe(q -> System.out.println("You said: " + q));

    }
}

    What is your name?
    Sir Lancelot
    You said: Sir Lancelot
    What is your quest?
    To seek the holy grail
    You said: To seek the holy grail
    What is your favorite color?
    BACK
    What is your quest?

我要做的是將索引作為 BehaviorSubject 並在我必須在問題之間切換時調用 onNext :

Scanner scanner = new Scanner(System.in);

String[] questions = {
        "What is your name?",
        "What is your quest?",
        "What is your favorite color?",
        "What is the capital of Assyria?",
        "What is the velocity of an unladen swallow?"
};

String[] cache = new String[questions.length];

BehaviorSubject<Integer> index = BehaviorSubject.create(0);

index
.observeOn(Schedulers.trampoline())
.concatMap(idx -> {
    if (idx == questions.length) {
        index.onCompleted();
        return Observable.empty();
    }

    System.out.println(questions[idx]);
    String answer = scanner.nextLine().trim();

    if ("BACK".equals(answer)) {
        index.onNext(Math.max(0, idx - 1));
        return Observable.empty();
    } else
    if ("QUIT".equals(answer)) {
        index.onCompleted();
        return Observable.empty();
    }

    cache[idx] = answer;
    index.onNext(idx + 1);
    return Observable.just(answer);
})
.subscribe(v -> System.out.println("You said: " + v));

我想如果Observable是有限的並且具有可管理的排放數量(如果每個都需要用戶輸入應該是這種情況),我想有一種方法。 您可以將其收集到toList()並從該列表中創建一個新的Observable 然后,您可以控制迭代並使用布爾標志隨時發出倒帶信號。

public class Test {

    public static void main(String[] args) {

        final Scanner scanner = new Scanner(System.in);
        final AtomicBoolean rewind = new AtomicBoolean();

        Observable.just(
                "What is your name?",
                "What is your quest?",
                "What is your favorite color?",
                "What is the capital of Assyria?",
                "What is the velocity of an unladen swallow?"
        ).toList().concatMap(l -> Observable.create(s -> {
            for (int i = 0; i < l.size(); i++) {
                s.onNext(l.get(i));
                if (rewind.getAndSet(false) &&  i >= 1) {
                    i = i - 2;
                }
            }
            s.onCompleted();
        }))
        .doOnNext(System.out::println)
        .concatMap(q -> Observable.create(s -> {
                    String answer = scanner.nextLine().trim();

                    if (answer.toUpperCase().equals("BACK")) {
                        rewind.set(true);
                    }
                    s.onNext(answer);
                    s.onCompleted();
                })
        ).filter(s -> !s.equals("BACK")).subscribe(q -> System.out.println("You said: " + q));

    }
}

What is your name?
Sir Lancelot of Camelot
You said: Sir Lancelot of Camelot
What is your quest?
To seek the Holy Grail
You said: To seek the Holy Grail
What is your favorite color?
Blue
You said: Blue
What is the capital of Assyria?
Asher
You said: Ashur
What is the velocity of an unladen swallow?
BACK
What is the capital of Assyria?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM