1

I'm using RxSearchView to emit out the results of a search query from an API to a recyclerview. However, if one of those query fails, onError() is called(which is expected) but the subscription as a whole is also canceled. Subsequent queries are not executed at all.

How should i modify the code so that the call to onError() is prevented when a query fails and the next incoming queries are executed normally?

Here's a code snippet:

subscription = RxSearchView.queryTextChanges(searchView)
                .debounce(500, MILLISECONDS)
                .filter(charSequence -> !TextUtils.isEmpty(charSequence))
                .map(CharSequence::toString)
                .subscribeOn(AndroidSchedulers.mainThread())
                .observeOn(Schedulers.io())
                .switchMap(query -> apiService.getSearchResults(query))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<SearchResponse>() {
                    @Override
                    public void onCompleted() {
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(SearchResponse searchResponse) {
                        if (searchResponse.getStatus().equals("OK")) {
                            //update Adapter
                        } else {
                            //update error views
                        }
                    }

                }); 

P.S: I am using switchMap() so that the results of old queries are ignored, if the results of new query has arrived.

div
  • 1,475
  • 3
  • 22
  • 32
  • You just need to wire the necessary error handling logic (https://github.com/ReactiveX/RxJava/wiki/Error-Handling-Operators) to the apiService.getSearchResults(query) call. – nikis Feb 24 '17 at 20:33

1 Answers1

3

You have to handle this error and return an object instead. You can do it, for example, by using onErrorResumeNext operator with apiService.getSearchResults(query) call. What you are going to return - depends on you, you can even return null if you want, but better to create some wrapper which can carry both response status flag and normal response if received.

Something like:

subscription = RxSearchView.queryTextChanges(searchView)
            .debounce(500, MILLISECONDS)
            .filter(charSequence -> !TextUtils.isEmpty(charSequence))
            .map(CharSequence::toString)
            .subscribeOn(AndroidSchedulers.mainThread())
            .observeOn(Schedulers.io())
            .switchMap(query -> apiService
                                   .getSearchResults(query)
                                   .onErrorResumeNext(error -> null)
            )
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Subscriber<SearchResponse>() {
                @Override
                public void onCompleted() {
                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onNext(SearchResponse searchResponse) {
                    if (searchResponse != null && searchResponse.getStatus().equals("OK")) {
                        //update Adapter
                    } else {
                        //update error views
                    }
                }

            }); 

Of course, this is naive example with using null, in reality you need to write error handling logic. Better to return wrapper, because if using RxJava 2, then it doesn't support null.

nikis
  • 11,166
  • 2
  • 35
  • 45
  • Thanks a lot. Also, what if i return null and check for null SearchResponse in onNext? Would that be a correct approach? – div Feb 24 '17 at 20:49
  • it should. But keep in mind, that if you migrate to RxJava 2, then you can have different behavior - https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#nulls – nikis Feb 24 '17 at 20:50
  • 1
    I would suggest that you use `.onErrorResumeNext(error -> Observable.empty())`, this way you won't need null checks. – Tassos Bassoukos Feb 25 '17 at 07:27