Search code examples
androidretrofit2rx-androidrx-bindingrx-java2

AutoCompleteTextView with Retrofit 2, RxJava and RxBinding


I am new to Rx world and try to implement my AutoCompleteTextView with RxJava, RxBinding and Retrofit 2.

Here's what I come up with which is troublesome: (Maybe I'm not doing it in the right way.)

I have an AutoCompleteTextView and here I created my subscribtion and observables:

subcription = RxTextView.textChangeEvents(clearableEditText)
                .skip(1)
                .debounce(400, TimeUnit.MILLISECONDS)
                .map(new Func1<TextViewTextChangeEvent, String>() {
                    @Override
                    public String call(TextViewTextChangeEvent textViewTextChangeEvent) {
                        return textViewTextChangeEvent.text().toString();
                    }
                })
                .filter(new Func1<String, Boolean>() {
                    @Override
                    public Boolean call(String s) {
                        return s.length() > 2;
                    }
                })
                .flatMap(new Func1<String, Observable<List<String>>>() {
                    @Override
                    public Observable<List<String>> call(String text) {
                        return searchService.getAutoCompleteTermsObservable(text)
                                .subscribeOn(Schedulers.io())
                                .observeOn(AndroidSchedulers.mainThread());
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<List<String>>() {
                    @Override
                    public void onCompleted() {
                        Log.d("rx", "oncomplete");
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("rx", e.toString());
                    }

                    @Override
                    public void onNext(List<String> strings) {
                        Log.d("rx", strings.size()+"");
                        autoAdapter = new ArrayAdapter<>(MainActivity.this,
                                android.R.layout.simple_dropdown_item_1line, strings);
                        clearableEditText.setAdapter(autoAdapter);
                        clearableEditText.showDropDown();
                    }
                });

My issue is when I set my EditText with setText() method, it triggers dropdown. For example it does that when I set the word from AutoCompleteTextView's dropdown and when I set it with voice input. Is there a way to avoid triggering onTextChanged when I set it manually? Or how can I fix that?


Solution

  • You could indeed use unsubscribe() but depending on how you set the value, you also use skipWhile. Here is an example:

    public void handleTextChanges() {
        final String textFromSource = "an";
    
        Observable.fromArray("a", "an", "ancestor")
                .skipWhile(new Predicate<String>() {
                    @Override
                    public boolean test(String value) throws Exception {
                        return textFromSource.contains(value);
                    }
                })
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String value) throws Exception {
                        Log.d("Rx", value);
                    }
                });
    }
    

    This will only consume ancestor (example is RxJava2, but the same methods exist). Any subsequent values, even if they match an, will be consumed. You could use filter if you always want to do the check like this