Implementing Search Using RxJava

Original author: Amit Shekhar
  • Transfer
  • Tutorial
This article will discuss the optimal and compact search implementation using RxJava for Android, eliminating unnecessary results and reducing the number of useless network calls.

Search Example
The original was written on October 16, 2017. Translation is free.

Currently, most of the applications that we use daily provide the ability to quickly search. Therefore, the implementation of the search is an important task. As developers, it’s important for us to implement the search in a better way.

Let's see how to implement a search in the best way using RxJava. Remember, RxJava has operators for everything .

Personally, I believe that you can solve any problem very easily using RxJava, which can be very difficult without RxJava. RxJava is a great technology.

Take a look at the RxJava elements that we will use to implement the search:

  • Publish Subject: If you have not come across this operator, then take a look at this article.
  • Filter
  • Debounce
  • DistinctUntilChanged
  • Switchmap

Let's start


First you need to make SearchView observable. Let's make it using PublishSubject. I am using SearchView from Android. View can be anything with functionality like EditText. To implement observable, you need to implement a listener to change the text in the field.

public class RxSearchObservable {
    public static Observable fromView(SearchView searchView) {
        final PublishSubject 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;
    }
Note from ConstOrVar :
Observable for SearchView will not work correctly. You subscribe to it in onCreate (), but when onQueryTextSubmit () is triggered, it will be unsubscribed, since onComplete is called. It turns out that the repeated search will not work. For repeated searches to work, you need to get rid of subject.onComplete ();
Note from Scrobot and BFS :
You should not use Subject, it exists for only 1 purpose: to combine the imperative style with the reactive one. Better to use Observable.create (). Search is exactly the case when you need to think about Backpressure, and since almost everyone uses RxJava2 today, this problem is solved there using Flowable, and it’s better to refactor this case.
Next, you need to call the created method and add operator calls, as in the example below.

RxSearchObservable.fromView(searchView)
                .debounce(300, TimeUnit.MILLISECONDS)
                .filter(new Predicate() {
                    @Override
                    public boolean test(String text) throws Exception {
                        if (text.isEmpty()) {
                            return false;
                        } else {
                            return true;
                        }
                    }
                })
                .distinctUntilChanged()
                .switchMap(new Function>() {
                    @Override
                    public ObservableSource apply(String query) throws Exception {
                        return dataFromNetwork(query);
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer() {
                    @Override
                    public void accept(String result) throws Exception {
                        textViewResult.setText(result);
                    }
                });

Now let's discuss why these operators are used and how they work together .

Debounce


The time parameters are passed to this operator. In this case, it catches events of user input of text, for example, “a”, “ab”, “abc”. Input often happens very quickly and this is fraught with a lot of network calls. But the user is usually only interested in the results for "abc". So, you need to drop the execution of queries for "a", "ab". The debounce statement is in a hurry to help. It expects user inactivity for the time passed in the parameter. If any input is made during the wait, the wait counter will be reset, the countdown will start again, the previous transmitted result, for example, “a”, will be discarded. Thus, the debounce statement passes down the chain only those elements that lasted without triggering new events during the specified timeout.
debounce example image

Filter


This operator is used to filter out unwanted lines, for example, an empty line, to avoid unnecessary network calls.

DistinctUntilChanged


This operator is used to avoid duplication of network calls. For example, the last search query was “abc”, then the user deleted “c” and re-entered “c”. The result is again abc. If the network call is already in the process with the same parameter, the distinctUntilChanged statement will not allow the same call to be made again. Thus, the distinctUntilChanged operator eliminates repeating elements that are subsequently passed to it.
distinctUntilChanged example image

Switchmap


In this example, this operator is used to exclude network calls whose results no longer need to be shown to the user. For example, the last search query was “ab” and there is a working network call for this query, but the user enters “abc” at this time. The result for "ab" is no longer needed, only the result for "abc" is needed. SwitchMap to the rescue. It passes further the results of only the last query, ignoring the rest.

Javadoc describes switchMapas follows:

Returns a new one Observable, applying the passed function for each item received Observable, but passing further items created only by the last received one Observable.

We did it! Just imagine how difficult it would be to implement a search without RxJava.

If you want to consider a complete example, then take a look at the next project .

Also popular now: