raklos
raklos

Reputation: 28545

Merging results using RxJava, handling error

I have code that invokes 2 apis and merges the results. using retrofit and rxJava.

How can I handle it so that if there is a problem with one of the api's i can still get the result from one of the api's that did work?

 IPlaces api = adapter.create(IPlaces.class); //endpoint1
     IPlaces api2 = adapter2.create(IPlaces.class); //endpoint2

    Observable.combineLatest(
            api.getPlacesFrom1("key", placeId),
            api2.getPlacesFrom2(placeId),
        new Func2<PlaceDetailResult1, PlaceDetailResult2, MergedReviews>() {
            @Override
            public MergedReviews call(PlaceDetailResult placeDetailResult1, PlaceDetailResult2 placeDetailResult2) {
                // processToMerge(  placeDetailResult1, placeDetailResult2)
                return mr;
            }

            })
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Observer<MergedReviews>() {
                @Override
                public void onCompleted() {

                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onNext(MergedReviews mr) {

                    SetAdapter(mr.reviews);
                    SetPhotosAdapter(mr.photos);
                }
            });

Upvotes: 2

Views: 1944

Answers (1)

Peter Barmettler
Peter Barmettler

Reputation: 621

As outlined in the comments, you can transform exceptions into null objects (or any other object) using onError*.

Here is a minimal example which I believe captures your setting. It takes two integer observables which provide one Integer value and combines them in some way. If one of the observables yields an error the other value is transmitted, if both yield an error a RuntimeException is thrown. I use zipWith instead of combineLatest since this is sufficient for your case where exactly one value is expected from each of the two observables.

Observable<Integer> zipThrowing(Observable<Integer> observable1, Observable<Integer> observable2) {
        return observable1.onErrorReturn(ex-> null)
                .zipWith(observable2.onErrorReturn(ex->null),
                        (a,b)->{
                            if(b == null) {
                                if(a==null){
                                    throw new RuntimeException("None of the two values are valid.");
                                }
                                return a;
                            }
                            if(a==null) {
                                return b;
                            }
                            return a+b;
                        }
                );

Transforming exceptions into null values may be unacceptable in some cases. If you need the information in your exception I suggest you use a result object containing either the actual value or the exception.

Upvotes: 2

Related Questions