1

我正在使用 RxAndroid 库学习 RxJava,同时使用 Retrofit 进行网络,并使用 RetroLambda 使用 Java8 lambdas。

我希望构建的应用程序具有以下功能:

  • 允许用户输入对 Wikipedia API 的查询
  • 键入后等待 1 秒,直到完成网络调用
  • 当应用程序“忙”获取结果时显示进度指示器
  • 进度指示器在键入后立即启动,而不是在 1 秒后,并在收到结果或错误时结束

我让它像这样工作:

// emit when text is changed
Observable<OnTextChangeEvent> textStream = WidgetObservable.text(mEditText);
Observable<OnTextChangeEvent> debouncedStream = textStream.debounce(1, TimeUnit.SECONDS); // Unchecked assignment

// start activity indicator immediately
textStream
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(s -> mProgressBar.setVisibility(View.VISIBLE));

debouncedStream
        .map(t -> wikiService.search(t.text().toString())) // query wikipedia
        .map(Object::toString)
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(s -> {
            mTextView.setText(s == null ? "Error" : s);
            mProgressBar.setVisibility(View.GONE);
        });

现在,我希望添加一个新的小部件,以允许我的维基百科查询使用另一种语言。现在,我将选择一个 Switch,“en”或“nl”作为 wikipedia url 的前缀。

用户与其交互之前的 GUI

所以我从 Switch 制作了一个新的 Observable,它会发出OnCheckedChangeEvents。

我的想法是,我需要将此 Observable 与textStream.

当开关翻转时,应该运行基本相同的功能,但不完全。当前正在运行的查询(如果正在运行)变得过时了,因为 url 前缀会改变。它应该再等待 1 秒钟,然后开始一个新的网络调用。

显然以下方法不起作用:

// emit when Switch is flipped
Observable<OnCheckedChangeEvent> languageSwitchStream = WidgetObservable.input(mLanguageSwitch);

// emit when text is changed
Observable<OnTextChangeEvent> textStream = WidgetObservable.text(mEditText);

// combine these 2, but they are using different types
Observable uiChangeStream = Observable.merge(textStream, languageSwitchStream);

Observable<OnTextChangeEvent> debouncedStream = uiChangeStream.debounce(1, TimeUnit.SECONDS); // Unchecked assignment

我不能只合并textStreamand languageSwitchStream

所以问题变成了:我应该如何使用正确的 Rx 来解决这个问题?

== 解决方案 ===========================

// emit when Switch is flipped
Observable<OnCheckedChangeEvent> languageSwitchStream =
        WidgetObservable
                .input(mLanguageSwitch)
                .startWith(new OnCheckedChangeEvent() {
                    @Override
                    public CompoundButton view() {
                        return null;
                    }

                    @Override
                    public boolean value() {
                        return mLanguageSwitch.isChecked();
                    }
                });

// emit when text is changed
Observable<OnTextChangeEvent> textStream = WidgetObservable.text(mEditText);

Observable<OnTextChangeEvent> uiChangeStream = Observable
        .combineLatest(
                textStream,
                languageSwitchStream,
                (text, switchValue) -> text);

uiChangeStream
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(s -> mProgressBar.setVisibility(View.VISIBLE));

uiChangeStream
        .debounce(1, TimeUnit.SECONDS)
        .map(t -> wikiService.search(t.text().toString())) // query wikipedia
        .map(Object::toString)
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(s -> {
            mTextView.setText(s == null ? "Error" : s);
            mProgressBar.setVisibility(View.GONE);
        });

扩展批准的答案,我.startsWith()在 Switch 的 Observable 中添加了一个,否则它会一直等待它被翻转,然后再发出一个值。

4

1 回答 1

1

使用CombineLatest并执行以下操作:

Observable<SearchParams> uiChangeStream = Observable.combineLatest(
    textStream, 
    languageSwitchStream,
    (text, switch) -> /* extract info from each and return search params */)
.map(searchParams -> wikiService.search(searchParams);

combineLatest()当一个 Observable 发出一个新值时,将重新发出另一个 Observable 的最后一个值。

于 2015-04-13T20:08:43.070 回答