Open In App

Implement Search Using RxJava Operators

Last Updated : 11 Aug, 2021
Improve
Improve
Like Article
Like
Save
Share
Report

Nowadays, most of the programs we use in our everyday lives include a search option that allows us to easily find what we’re looking for. As a result, having a search tool is critical. And it is our job as developers to implement it better. Let’s look at how to do it better with the RxJava Operators.

Image 1. The RxSearch as in GfG.

The following RxJava features will be used to build this search feature:

Prerequisite: We will need to know the basic RxJava functions, as implementing search is somewhat high order.

Whoa! although this may sound like implementing a search is really tough, but NO. It’s really easy when we do it stepwise as mentioned below in this article, and you will be up and running in no time. Moreover, all the terms above are linked to other awesome GfG articles to extend your learning! Without further ado, let’s start.

Step by Step Implementation

Step #1: Making search view Observable

First and foremost, you must make the SearchView visible. Let’s use the PublishSubject to make the SearchView observable. Here we are making use of the Android SearchView. The view may be anything that looks like EditText. It’s only that you’ll need to build the text change listener to make that view visible.

Java




public class GfGSearch {
    public static Observable<String> fromView(SearchView gfgSearch) {
        final gfgArticle<String> article = gfgArticle.create();
        gfgSearch.setOnQueryTextListener(new gfgSearch.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String s) {
                article.onComplete();
                return true;
            }
  
            @Override
            public boolean onQueryTextChange(String text) {
                article.onNext(text);
                return true;
            }
        });
  
        return article;
    }
}


Step #2: Applying the Operators

You must use the following operations on that SearchView observable:

Java




@Override
public ObservableSource<String> apply(String query)
        {
            return dataFromNetwork(query)
                .doOnError(throwable
                           -> {
                              // Exception Handling
                           })
                .onErrorReturn(throwable -> "");
        }
    })
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Consumer<String>() {
        @Override public void accept(String result)
        {
            searchResult.setText(result);
        }
    });
RxGfGSearch.fromView(searchView)
    .debounce(200, TimeUnit.MILLISECONDS)
    .filter(new Predicate<String>() {
        @Override public boolean test(String text)
        {
            if (text.isEmpty()) {
                searchResult.setText("Spandan");
                return false;
            }
            else {
                return true;
            }
        }
    })
    .distinctUntilChanged()
    .switchMap(new Function<String, ObservableSource<String> >() {


Understanding the Terms which we used in the above code:

DistinctUntilChanged: The distinctUntilChanged operator prevents repeated network calls. Assume the most recent ongoing search query was “abc,” and the user erased “c” before typing “c” again. So it’s “abc” once more. So, if a network call is already in progress with the search query “abc,” it will not initiate a duplicate call with the search query “abc.” As a result, distinctUntilChanged prevents the source Observable from emitting duplicate successive items.

  • Filter: The filter operator is used to filter out undesirable strings, such as the empty string in this example, in order to avoid making an unnecessary network call.
  • Debounce: The debounce operator is employed with a time constant in this case. When a user inputs “a”, “ab”, or “abc” in a brief period of time, the debounce operator handles the situation. As a result, there will be an excess of network calls. However, the user is ultimately interested in the result of the search “abc.” As a result, the outcomes of “a” and “ab” must be discarded. Ideally, no network calls for “a” and “ab” because the user wrote those in a very short period of time. As a result, the debounce operator steps in to help. If another search query arrives in between that time, the debounce will discard the old item and start waiting for that time again with the new search query. If nothing new arrives within that constant time period, it will return to that search query for additional processing. As a consequence, debounce will only emit an item from an Observable if a certain timespan has passed without another item being emitted. 
  • SwitchMap: The switchMap operator is used here to prevent network call results that are no longer required for showing to the user. Assume the most recent search query was “ab,” there is an active network call for “ab,” and the user entered “abc.” Then you’re no longer interested in the outcome of “ab.” You are just concerned with the outcome of “abc.” As a result, the switchMap comes to the rescue. It only returns the results of the most recent search query and ignores the others.

Geek Tip #1: Returns a new Observable by applying the given function to each item emitted by the source.

Conclusion

And yes, that’s pretty much it for this article, by this you would now be able to implement a RxSearch using RxJava, this search is used in many places throughout like Netflix, Google, and even Geeks for Geeks. Imagine how tough the world would be without Rx!

Always Remember:
There is something for everything in RxJava!



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads