Mes
Mes

Reputation: 1691

Execute multiple different retrofit calls that depend on a single RxTextView

I have an EditText and right below it there are four tabs in a ViewPager and what I'm currently doing is executing a request to a Rest service using Retrofit when text changes.

 RxTextView.textChangeEvents(searchbar.getEditText())
            .debounce(400, TimeUnit.MILLISECONDS)
            .filter(new Func1<TextViewTextChangeEvent, Boolean>() {
                @Override
                public Boolean call(TextViewTextChangeEvent text) {
                    return (text.text().length() > 2);
                }
            })
            .subscribeOn(AndroidSchedulers.mainThread())
            .observeOn(Schedulers.io())
            .switchMap(new Func1<TextViewTextChangeEvent, Observable<?>>() {
                @Override
                public Observable<?> call(TextViewTextChangeEvent textViewTextChangeEvent) {
                    String searchBarText = textViewTextChangeEvent.text().toString();

                    switch (visibleTab) {
                        case TAGS:
                            return presenter.executeSearchPostsByTag(searchBarText, String.valueOf(0));
                        case PEOPLE:
                            return presenter.executeSearchPostsByPeople(searchBarText, String.valueOf(0));
                        case COMPANIES:
                            return presenter.executeSearchPostsByCompanies(searchBarText, String.valueOf(0));
                        case JOBS:
                            return presenter.executeSearchPostsByJobs(searchBarText, String.valueOf(0));
                        default:
                            return presenter.executeSearchPostsByTag(searchBarText, String.valueOf(0))
                                    .toCompletable().toObservable();
                    }

                }
            })
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Observer<Object>() {
             // here I use EventBus to pass the results to the Fragments (Tabs)
             // ... code omitted ...

As you can notice from the code for each Tab I have a different request.

But now the requirements have changed and for every text change there is in the EditText I have to execute all four requests concurrently.

I searched a lot and what I have found out is that I can use combineLatest' so I added all four calls tocombineLatest` but since they all depend on text changes nothing happened.

    Observable.combineLatest(presenter.executeSearchPostsByTag( /** what to add as queryText **/ ), 
         presenter.executeSearchPostsByJobs(/** what to add here as queryText**/), //omits the other two calls)

As you see right above I don't know how to pass the queryText. There must be a way combining the combineLatest code with the RxTextView.textChangeEvents(searchbar.getEditText())... code until the switchMap I posted at the beginning but I couldn't find it.

EDIT : well maybe combineLatest was wrong, and I could do something like :

                .map(new Func1<String, Boolean>() {
                @Override
                public Boolean call(String s) {

                    presenter.executeSearchPostsByTag(s, String.valueOf(0));
                    presenter.executeSearchPostsByPeople(s, String.valueOf(0));
                    presenter.executeSearchPostsByJobs(s, String.valueOf(0));
                    presenter.executeSearchPostsByCompanies(s, String.valueOf(0));

                    return true;

                }
            })

but then I don't know how to get the results to the subscriber

Upvotes: 0

Views: 295

Answers (1)

Geoffrey Marizy
Geoffrey Marizy

Reputation: 5521

You are close. Just replace the switchmap with:

.flatMap(new Func1<TextViewTextChangeEvent, Observable<CombinedData>>() {
    @Override
    public Observable<CombinedData> call(TextViewTextChangeEvent textViewTextChangeEvent) {
        String searchBarText = textViewTextChangeEvent.text().toString();

        return Observable.combineLatest(
                presenter.executeSearchPostsByTag(searchBarText, String.valueOf(0)), 
                presenter.executeSearchPostsByPeople(searchBarText, String.valueOf(0)),
                ...);
        }    
})

For better readability, create a method to extract the combine part. Something like:

Observable<CombinedData> fetchData(String searchBarText) {
    return Observable.combineLatest(
            presenter.executeSearchPostsByTag(searchBarText, String.valueOf(0)),
            presenter.executeSearchPostsByPeople(searchBarText, String.valueOf(0)),
            ...);
}

But if you can, it would be better to split it in four pieces. Declare an Observable:

Observable<TextViewTextChangeEvent> requestObservable = RxTextView.textChangeEvents(searchbar.getEditText())
        .debounce(400, TimeUnit.MILLISECONDS)
        .filter(new Func1<TextViewTextChangeEvent, Boolean>() {
            @Override
            public Boolean call(TextViewTextChangeEvent text) {
                return (text.text().length() > 2);
            }
        })
        .subscribeOn(AndroidSchedulers.mainThread())
        .observeOn(Schedulers.io());

Then you subscribe four times, for each request:

.flatMap(new Func1<TextViewTextChangeEvent, Observable<Post>>() {
    @Override
    public Observable<Post> call(TextViewTextChangeEvent textViewTextChangeEvent) {
        String searchBarText = textViewTextChangeEvent.text().toString();
        return presenter.executeSearchPostsByTag(searchBarText, String.valueOf(0));
        }
})
.subscribe(...

Upvotes: 1

Related Questions