2016-09-18 198 views
8

當用戶類型分爲SearchView小部件,應用程序應該作出 API調用(在後臺線程)從服務器獲取搜索結果,並且(在UI線程)在RecyclerView顯示它們。如何使用SearchView,Retrofit和RxJava(RxBindings)實現搜索功能?

我使用下面的代碼在我的片段:

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

retrofit2.adapter.rxjava.HttpException: HTTP 422 

然後,當我輸入我的搜索查詢retrofitService.search(query)不再被調用。

回答

14

請記住,您實際上可以在您的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

+2

否則,你可以在配置改造時指定IO線程 - .addCallAdapterFactory(RxJavaCallAdapterFactory.create(調度器.io)) – Outofdate

+0

是的,然後'.observeOn(Schedulers.io())'是不必要的 –