[英]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.