Search code examples
androidandroid-edittextrx-binding

How to process distinct values using RxBinding RxTextView.textChangeEvents


I am using RxBinding in my current Android application and wish to implement a text search feature.

My code is as follows:-

compositeDisposable.add(RxTextView.textChangeEvents(searchEditText)
                .skipInitialValue()
                .subscribeOn(Schedulers.io())
                .debounce(200, TimeUnit.MILLISECONDS)
                .filter(textViewTextChangeEvent -> (textViewTextChangeEvent.text().length() == 0 || textViewTextChangeEvent.text().length() > 2))
                .map(event -> event.text().toString())
                .distinct()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(charactersResponse -> {
                    articlesLiveData = viewModel.textSearch(charactersResponse);
                    textLiveData.removeObserver(TextFragment.this);
                    textLiveData.observe(TextFragment.this, TextFragment.this);
                }));

I want to only search for distinct values, however the code above makes duplicate search requests.

Why isn't distinct removing duplicate strings?

For example when I type "chilean" into my Search EditText

my search code is called with the following strings

chi
chi
chil
chil
chil
chile
chile
chilea
chilean
chilean

What am I doing wrong?


Solution

  • Without more context I can't really be sure but it seems like the subscription has been made twice. You said you put this code in Fragment::onViewCreated, so maybe you are loading another fragment and then coming back to this one without disposing of the first subscription? You can put a breakpoint where you make the subscription to see if it is getting called twice. If it only gets called once and you still have this problem I will need to see more of your code to diagnose it.

    When I copy your code into Activity::onCreate it works as expected. So the first thing you can do is make sure you are disposing your compositeDisposable in Fragment::onDestroyView. That should fix the multiple-emission problem.

    Now you will have another problem: you are using distinct(), but I doubt that's what you want from a search bar. Distinct will filter ALL non-unique values for the lifetime of the observable. So once it has emitted "chile", if you continue to type "chilean" and then erase "an", you will never see "chile" again. What you probably want is distinctUntilChanged(), which just filters out non-unique matches to the LAST emitted value.