2016-09-18 5 views
8

Wenn der Benutzer in die SearchView widget, sollte die Anwendung einen API-Aufruf (im Hintergrund-Thread) macht Suchergebnisse von dem Server zu holen, und zeigt sie (in UI-Thread) in RecyclerView.Wie implementiert man Suchfunktion mit SearchView, Retrofit und RxJava (RxBindings)?

Ich verwende den folgenden Code in meinem 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(...) 
        } 
       }); 
} 

Aber ich erhalte eine Ausnahme:

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) 
... 

Als ich .subscribeOn(Schedulers.io()), die Suche API-Aufruf entfernen wird ausgelöst, wenn Fragment erstellt und Keine Abfrage ist in SearchView eingegeben und ich bekomme Ausnahme

retrofit2.adapter.rxjava.HttpException: HTTP 422 

dann, wenn ich meine Suchanfrage eingeben retrofitService.search(query) wird nicht mehr aufgerufen.

Antwort

14

Denken Sie daran, dass Sie mehrere Operatoren observeOn und mehrere subscribeOn in Ihrer RX-Kette verwenden können.

Try this:

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(...) 
       } 
      }); 

Dies wird grundsätzlich zu diesem Thema Nutzung führen:

thread usage

+2

Ansonsten können Sie Io Thread angeben, wenn Retrofit konfigurieren - .addCallAdapterFactory (RxJavaCallAdapterFactory.create (Schedulers .io)) – Outofdate

+0

yep, und dann '.observeOn (Schedulers.io())' wäre unnötig –

Verwandte Themen