I have a search functionality in my Android app. The searchView has callback onSearchTextChanged(String oldQuery, String newQuery)
. This callback function calls every time user enters any text to search field. I have a REST call in this callback which is triggering every time each word is being typed. Which leads to multiple calls for REST. I want to avoid that. I just want only one instance active at a time which is latest one and all other calls should be canceled instantly whenever the new letter is typed. Below are code details.
@Override
public void onSearchTextChanged(String oldQuery, String newQuery) {
floatingSearchView.showProgress();
moviesAPI.searchQuery(newQuery)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Search>() {
@Override
public void onCompleted() {
Log.d(TAG, "onCompleted() called");
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "onError() called with: e = [" + e + "]");
}
@Override
public void onNext(Search search) {
floatingSearchView.hideProgress();
floatingSearchView.swapSuggestions(search.getSearchResults());
Log.d(TAG, "onNext() called with: search = [" + search + "]");
}
}
);
}
You probably want to use debounce to delay search requests while typing (and only after user stops typing for x duration).
Additionally, for canceling older requests when new request arrive you may transform the text changes events to stream of event (either manually or using library like RxBindings), and then switchMap each new text event to query. switchMap operator will cancel previous request that still going, when new request arrive driven by new search text stream.
you can found various examples of implementing search suggestions for android with rxjava, like this one by Kaushik Gopal: instantauto-searching-text-listeners-using-subjects--debounce
code sample, this sample uses RxBinding library for easily getting textChanages events as Observable stream.
RxTextView.textChangeEvents(tv)
.debounce(300, TimeUnit.MILLISECONDS)
.switchMap(new Func1<TextViewTextChangeEvent, Observable<SearchResult>>() {
@Override
public Observable<SearchResult> call(
TextViewTextChangeEvent textViewTextChangeEvent) {
return moviesAPI.searchQuery(textViewTextChangeEvent.text().toString())
.subscribeOn(Schedulers.io());
}
})
.subscribe(new Subscriber<SearchResult>() {
@Override
public void onCompleted() {
Log.d(TAG, "onCompleted() called");
}
@Override
public void onError(Throwable e) {
floatingSearchView.hideProgress();
Log.d(TAG, "onError() called with: e = [" + e + "]");
}
@Override
public void onNext(SearchResult search) {
floatingSearchView.hideProgress();
floatingSearchView.swapSuggestions(search.getSearchResults());
Log.d(TAG, "onNext() called with: search = [" + search + "]");
}
});