webo80
webo80

Reputation: 3393

Handle network error on Retrofit + RxJava2 + Room

I'm struggling while figuring how to raise a network error from the data layer to the view layer.

I'm using Room along with RxJava2 and Retrofit2. I'm implementing the repository pattern as local-first, so I query the local data, while fetching from the remote, and updating local data if neccesary. In code, this would be:

public Flowable<List<DEvent>> getAll() {
    return db.dEventDataStore().getAll()
        .doOnSubscribe(new Consumer<Subscription>() {
            @Override
            public void accept(final Subscription subscription) throws Exception {
                dEventApi.getAll().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new MaybeObserver<List<DEvent>>() {
                        @Override
                        public void onSubscribe(@NonNull Disposable disposable) {
                            Timber.d("Remote onSubscribe");
                        }

                        @Override
                        public void onSuccess(@NonNull List<DEvent> dEvents) {
                            Timber.d("Remote onSuccess!");
                            db.dEventDataStore().insertAll(dEvents);
                        }

                        @Override
                        public void onError(@NonNull Throwable throwable) {
                            Timber.d("Remote onError!");
                        }

                        @Override
                        public void onComplete() {
                            Timber.d("Remote onComplete!");
                        }
                    }
                );
            }
        });
}

And in the view layer:

    mDisposable.add(repo.getAll()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Consumer<List<DEvent>>() {
                @Override
                public void accept(List<DEvent> dEvents) throws Exception {
                    Timber.d("OnNext!!");
                    mView.showEvents(dEvents);
                }
            }, new Consumer<Throwable>() {
                @Override
                public void accept(Throwable throwable) throws Exception {
                    Timber.e("Error on getting DEvents - " + Log.getStackTraceString(throwable));
                }
            }));

How can I emit that throwable?

Upvotes: 1

Views: 663

Answers (1)

yosriz
yosriz

Reputation: 10267

You're not chaining these Observables here - thus an error from the API Observable will not propagate down the stream to the view layer. (moreover I'm not sure how Room operate but you will query it twice for the DB updates)

If I understands correctly, db.dEventDataStore().getAll() created by Room so this Flowable is infinite, listen to DB changes and emit any change. so you want to query server, and in case of data update the DB and expect emission from Room's DB Flowable.

in this case, you can do this in parallel using merge, and the API Maybe, pass through just the errors by ignoring any elements it's emit. in this way the downstream we'll get the data emissions only from Room DB, while still getting server error notifications.

 public Flowable<List<DEvent>> getAll() {
    return Flowable.merge(
            db.dEventDataStore().getAll(),
            dEventApi.getAll()
                    .doAfterSuccess(dEvents -> db.dEventDataStore().insertAll(dEvents))
                    .ignoreElement()
                    .toFlowable()
    );
}

Upvotes: 1

Related Questions