作为Rxandroid入门的一个例子,我试图实现一个searchbox,当用户插入一些内容时,它会触发一个rest调用。
到目前为止,我有两个工作部分。第一次观察EditTextView…

RxTextView.textChangeEvents(searchEditText)
    .debounce(400, TimeUnit.MILLISECONDS)
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<TextViewTextChangeEvent>() {
            @Override
            public void onCompleted() {
                Timber.d("onCompleted");
            }

            @Override
            public void onError(Throwable e) {
                Timber.e(e, "onError");
                }

            @Override
            public void onNext(TextViewTextChangeEvent e) {
                Timber.d("onNext" + e.text().toString());
            }
        });

…第二部分通过使用改造服务调用rest api:
APIManager.getService().searchRestaurants("test")
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<List<Restaurant>>() {
            @Override
            public void onCompleted() {
                Timber.d("onCompleted");
            }

            @Override
            public void onError(Throwable e) {
                Timber.e(e, "onError");
            }

            @Override
            public void onNext(List<Restaurant> restaurants) {
                Timber.d("onNext");
                for (Restaurant restaurant : restaurants) {
                    Timber.d(restaurant.getId() + ": " + restaurant.getName());
                }
            }
        });

我的问题是把这两部分结合起来。我尝试使用flatMap运算符,如下所示:
RxTextView.textChangeEvents(searchEditText)
        .debounce(400, TimeUnit.MILLISECONDS)
        .observeOn(AndroidSchedulers.mainThread())
        .flatMap(new Func1<TextViewTextChangeEvent, Observable<List<Restaurant>>>() {
            @Override
            public Observable<List<Restaurant>> call(TextViewTextChangeEvent txtChangeEvt) {
                return APIManager.getService().searchRestaurants(txtChangeEvt.text().toString());
            }
        })
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<List<Restaurant>>() {
            @Override
            public void onCompleted() {
                Timber.d("onCompleted");
            }

            @Override
            public void onError(Throwable e) {
                Timber.e(e, "onError");
            }

            @Override
            public void onNext(List<Restaurant> restaurants) {
                Timber.d("onNext");
                for (Restaurant restaurant : restaurants) {
                    Timber.d(restaurant.getId() + ": " + restaurant.getName());
                }
            }
        });

当我这样做时,我会得到以下异常:
java.lang.IllegalStateException: Must be called from the main thread. Was: Thread[RxCachedThreadScheduler-1,5,main]
                                                                              at com.jakewharton.rxbinding.internal.Preconditions.checkUiThread(Preconditions.java:28)
                                                                              at com.jakewharton.rxbinding.widget.TextViewTextChangeEventOnSubscribe.call(TextViewTextChangeEventOnSubscribe.java:21)
                                                                              at com.jakewharton.rxbinding.widget.TextViewTextChangeEventOnSubscribe.call(TextViewTextChangeEventOnSubscribe.java:12)

所以我试图通过调用subscribeOn(AndroidSchedulers.mainThread()来解决这个问题,但在本例中,当然,我得到了networkonmainthread异常。
我该怎么做?
在不同的线程上执行的不同的观察值的组合方式是什么?

最佳答案

只需删除第一个.observeOn(AndroidSchedulers.mainThread())。看看这个example

Observable.just(1) // 1 will be emited in the IO thread pool
    .subscribeOn(Schedulers.io())
    .flatMap(...) // will be in the IO thread pool
    .observeOn(Schedulers.computation())
    .flatMap(...) // will be executed in the computation thread pool
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(); // will be executed in the Android main thread (if you're running your code on Android)

08-05 21:04