java - 如何使用 SearchView、Retrofit 和 RxJava (RxBindings) 实现搜索功能?

标签 java android retrofit rx-java rx-binding

当用户在 SearchView 小部件中输入内容时,应用程序应该制作一个 API 调用(在后台线程中)从服务器获取搜索结果,并在 RecyclerView 中显示它们(在 UI 线程中)。

我在 fragment 中使用了以下代码:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.my_fragment, menu);
    SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();

    SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
    searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName()));

    RxSearchView.queryTextChanges(searchView)
                .debounce(400, TimeUnit.MILLISECONDS)
                .map(CharSequence::toString)
                .switchMap(query -> retrofitService.search(query))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<List<Item>>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e(LOG_TAG, "Error", e);
                    }

                    @Override
                    public void onNext(List<Item> items) {
                        // adapter.addItems(...)
                    }
                });
}

但我得到一个异常(exception):

java.lang.IllegalStateException: Must be called from the main thread. Was: Thread[RxIoScheduler-2,5,main]
at com.jakewharton.rxbinding.internal.Preconditions.checkUiThread(Preconditions.java:35)
at com.jakewharton.rxbinding.support.v7.widget.SearchViewQueryTextChangesOnSubscribe.call(SearchViewQueryTextChangesOnSubscribe.java:18)
at com.jakewharton.rxbinding.support.v7.widget.SearchViewQueryTextChangesOnSubscribe.call(SearchViewQueryTextChangesOnSubscribe.java:10)
...

当我删除 .subscribeOn(Schedulers.io()) 时,会在创建 fragment 且未在 SearchView 中键入任何查询时触发搜索 API 调用,我得到异常

retrofit2.adapter.rxjava.HttpException: HTTP 422 

然后,当我输入搜索查询时,retrofitService.search(query) 不再被调用。

最佳答案

请记住,您实际上可以在 rx 链中使用多个 observeOn 和多个 subscribeOn 运算符。

试试这个:

RxSearchView.queryTextChanges(searchView)
            .debounce(400, TimeUnit.MILLISECONDS)
            .map(CharSequence::toString)
            .subscribeOn(AndroidSchedulers.mainThread())
            .observeOn(Schedulers.io())
            .switchMap(query -> retrofitService.search(query))
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Subscriber<List<Item>>() {
                @Override
                public void onCompleted() {

                }

                @Override
                public void onError(Throwable e) {
                    Log.e(LOG_TAG, "Error", e);
                }

                @Override
                public void onNext(List<Item> items) {
                    // adapter.addItems(...)
                }
            });

这基本上会导致线程使用:

thread usage

关于java - 如何使用 SearchView、Retrofit 和 RxJava (RxBindings) 实现搜索功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39558885/

相关文章:

java - 用于生成字母数字字符串的 RandomStringGenerator

java - 大堆上最坏情况垃圾收集持续时间大约是多少

android - 手机关机期间的 HTTP 调用

java - Android DownloadManager 获取文件名

android - native 与混合移动应用程序

android - Retrofit 2 中的错误处理是如何进行的?我找不到大多数解决方案建议的 RetrofitError 类?

android - 如何处理 "javax.net.ssl.SSLHandshakeException",改造错误响应?

java - Solaris 5.10 上的 UnsupportedCharsetException : IS646-US with JDK 1. 8u51

Java对象创建区别

java - Android javac和dx——麻烦处理,类名和路径不匹配