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

Max*_*Max 10 java android rx-java retrofit rx-binding

当用户键入SearchView窗口小部件时,应用程序应进行API调用(在后台线程中)以从服务器获取搜索结果,并在RecyclerView中显示它们(在UI线程中).

我在我的片段中使用以下代码:

@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(...)
                    }
                });
}
Run Code Online (Sandbox Code Playgroud)

但我得到一个例外:

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)
...
Run Code Online (Sandbox Code Playgroud)

当我删除时.subscribeOn(Schedulers.io()),在创建片段并且没有输入查询时触发搜索API调用SearchView,我得到了exeption

retrofit2.adapter.rxjava.HttpException: HTTP 422 
Run Code Online (Sandbox Code Playgroud)

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

Bar*_*ski 18

请记住,您实际上可以在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(...)
                }
            });
Run Code Online (Sandbox Code Playgroud)

这基本上会导致这个Thread使用:

线程用法

  • 否则,您可以在配置Retrofit时指定Io线程 - .addCallAdapterFactory(RxJavaCallAdapterFactory.create(Schedulers.io)) (2认同)