簡體   English   中英

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

[英]How to implement search feature with SearchView, Retrofit and RxJava (RxBindings)?

當用戶鍵入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(...)
                    }
                });
}

但我得到一個例外:

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()) ,在創建片段並且在SearchView沒有輸入查詢時觸發了搜索API調用,我得到了exeption

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使用:

線程用法

我在生產應用程序上使用這種方法。

 RxSearchView.queryTextChanges(searchView)
                    .debounce(300, TimeUnit.MILLISECONDS)
                    .filter(new Predicate<String>() {
                        @Override
                        public boolean test(String text) throws Exception {
                            if (text.isEmpty()) {
                                return false;
                            } else {
                                return true;
                            }
                        }
                    })
                    .distinctUntilChanged()
                    .switchMap(new Function<String, ObservableSource<String>>() {
                        @Override
                        public ObservableSource<String> apply(String query) throws Exception {
                            return dataFromNetwork(query);
                        }
                    })
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Consumer<String>() {
                        @Override
                        public void accept(String result) throws Exception {
                            textViewResult.setText(result);
                        }
                    });
  • DistinctUntilChanged:distinctUntilChanged運算符用於避免重復的網絡調用。 假設最后一個正在進行的搜索查詢是“abc”,用戶刪除了“c”並再次鍵入“c”。 所以它又是“abc”。 因此,如果網絡呼叫已經使用搜索查詢“abc”進行,則不會使用搜索查詢“abc”再次進行重復呼叫。 因此,distinctUntilChanged會抑制源Observable發出的重復連續項。
  • SwitchMap:這里,switchMap運營商用於避免網絡呼叫結果,這些結果對於向用戶顯示不再需要。 假設最后一個搜索查詢是“ab”,並且正在進行“ab”網絡調用,用戶鍵入“abc”。 那你就不再對“ab”的結果感興趣了。 您只對“abc”的結果感興趣。 因此,switchMap得救了。 它僅提供最后一次搜索查詢的結果(最近的)並忽略其余的搜索查詢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM