Instant Search Using RxJava Operators
- Authors
- Name
- Amit Shekhar
- Published on
I am Amit Shekhar, Co-Founder @ Outcome School, I have taught and mentored many developers, and their efforts landed them high-paying tech jobs, helped many tech companies in solving their unique problems, and created many open-source libraries being used by top companies. I am passionate about sharing knowledge through open-source, blogs, and videos.
Join Outcome School and get high paying tech job: Outcome School
Before we start, I would like to mention that, I have released a video playlist to help you crack the Android Interview: Check out Android Interview Questions and Answers.
In this blog, we will learn how to implement the instant search feature using RxJava operators in Android applications.
Nowadays, most of the applications that we use in our daily life come with a search feature which provides us a facility to get things very quickly we are looking for.
So, having a search feature is very important. And, we as a developer have a responsibility to implement it in a better way.
Let’s see how to implement it in a better way using the RxJava Operators.
Don’t forget: There is an operator for everything in RxJava.
I personally believe that we can solve any complex problem very easily with RxJava which can be very difficult without RxJava. RxJava is just awesome.
The following are the things of RxJava that we will be using to implement this search feature:
- Publish Subject: I have provided the simplest introduction to the RxJava Subject, please refer this blog to know more about the Subject in RxJava.
- Filter Operator
- Debounce Operator
- DistinctUntilChanged Operator
- SwitchMap Operator
We will discuss all the above one by one.
Let’s begin
First of all, you will have to make the SearchView observable. Let’s make the SearchView observable by using the PublishSubject. I am using the Android SearchView. The view can be anything like EditText. It is just that you will have to make that view observable by implementing the text change listener.
public class RxSearchObservable {
public static Observable<String> fromView(SearchView searchView) {
final PublishSubject<String> subject = PublishSubject.create();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
subject.onComplete();
return true;
}
@Override
public boolean onQueryTextChange(String text) {
subject.onNext(text);
return true;
}
});
return subject;
}
}
Then, on that SearchView observable, you will have to apply all the operators like below:
RxSearchObservable.fromView(searchView)
.debounce(300, TimeUnit.MILLISECONDS)
.filter(new Predicate<String>() {
@Override
public boolean test(String text) {
if (text.isEmpty()) {
textViewResult.setText("");
return false;
} else {
return true;
}
}
})
.distinctUntilChanged()
.switchMap(new Function<String, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(String query) {
return dataFromNetwork(query)
.doOnError(throwable -> {
// handle error
})
// continue emission in case of error also
.onErrorReturn(throwable -> "");
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
@Override
public void accept(String result) {
textViewResult.setText(result);
}
});
Now, it’s time to learn why these operators are being used and how they work in combination.
- Debounce: Here, the debounce operator is used with a time constant. The debounce operator handles the case when the user types “a”, “ab”, “abc”, in a very short time. So there will be too much network calls. But the user is finally interested in the result of the search “abc”. So, you must discard the results of “a” and “ab”. Ideally, there should be no network calls for “a” and “ab” as the user typed those in very short time. So, the debounce operator comes to the rescue. The debounce will wait for the provided time for doing anything, if any other search query comes in between that time, it will ignore the previous item and start waiting for that time again with the new search query. If nothing new comes in that given constant time, it will proceed with that search query for further processing. So, debounce only emit an item from an Observable if a particular timespan has passed without it emitting an another item.
- Filter: The filter operator is used to filter the unwanted string like empty string in this case to avoid the unnecessary network call.
- DistinctUntilChanged: The distinctUntilChanged operator is used to avoid the duplicate network calls. Let say the last on-going search query was “abc” and the user deleted “c” and again typed “c”. So again it’s “abc”. So if the network call is already going on with the search query “abc”, it will not make the duplicate call again with the search query “abc”. So, distinctUntilChanged suppress duplicate consecutive items emitted by the source Observable.
- SwitchMap: Here, the switchMap operator is used to avoid the network call results which are not needed more for displaying to the user. Let say the last search query was “ab” and there is an ongoing network call for “ab” and the user typed “abc”. Then you are no more interested in the result of “ab”. You are only interested in the result of “abc”. So, the switchMap comes to the rescue. It only provides the result for the last search query(most recent) and ignores the rest.
Returns a new
Observable
by applying a function that you supply to each item emitted by the sourceObservable
that returns anObservable
, and then emitting the items emitted by the most recently emitted of theseObservables
.
Yeah, we have done it. Just imagine how much complex the search implementation would have been without RxJava.
If you want to check the complete example, just clone the project and check the search implementation.
Prepare yourself for Android Interview: Android Interview Questions
That's it for now.
Thanks
Amit Shekhar
Co-Founder @ Outcome School
You can connect with me on:
Follow Outcome School on: