ReactiveX / RxJava

RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.
Apache License 2.0
47.88k stars 7.61k forks source link

Handling Network Error in Rxjava 2 - Retrofit 2 #4942

Closed mhdtouban closed 7 years ago

mhdtouban commented 7 years ago

How can we handle different network errors in Rxjava2 ?

We used to check the instance of the throwable if it's of IOException or HttpException back with Rxjava 1 ,however, in RxJava 2 the throwable error is of type GaiException.

code snippet


 RestAPI restAPI = RetrofitHelper.createRetrofitWithGson().create(RestAPI.class);

        Observable<BaseResponseTourPhoto> observable = restAPI.fetchData("Bearer " + getAccessToken(), "2", "" + page)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());

        Disposable subscription = observable.subscribe(BaseResponse-> {
            onLoadingFinish(isPageLoading, isRefreshing);
            onLoadingSuccess(isPageLoading, BaseResponse);
            writeToRealm(BaseResponse.getData());
        }, error -> {
            onLoadingFinish(isPageLoading, isRefreshing);
            onLoadingFailed(error);
        });

        mCompositeDisposable = new CompositeDisposable();
        mCompositeDisposable.add(subscription);

        unsubscribeOnDestroy(mCompositeDisposable);

   private void onLoadingFailed(Throwable error) {
        try {
            // We had non-200 http error
            if (error instanceof HttpException) {
                HttpException httpException = (HttpException) error;
                Response response = httpException.response();
                Log.i(TAG, error.getMessage() + " / " + error.getClass());
            }
            // A network error happened
            if (error instanceof IOException) {
                Log.i(TAG, error.getMessage() + " / " + error.getClass());
            }

            Log.i(TAG, error.getMessage() + " / " + error.getClass());
        } catch (Exception e) {
            Log.i(TAG, e.getMessage());
        }
    }```

reference: https://github.com/square/retrofit/issues/690
akarnokd commented 7 years ago

RxJava 2 doesn't do networking or signal such exception so it is up to Retrofit or the adapter what it signals. I suggest asking this on Stackoverflow instead or posting a bug report for the retrofit adapter itself.

mhdtouban commented 7 years ago

question posted on stackoverflow : http://stackoverflow.com/questions/41379815/handling-network-error-in-rxjava-2-retrofit-2

JakeWharton commented 7 years ago

UHE is a subclass of IO so checking instanceof still works.

On Thu, Dec 29, 2016, 8:08 AM Mohammed Touban notifications@github.com wrote:

question posted on stackoverflow : http://stackoverflow.com/questions/41379815/handling-network-error-in-rxjava-2-retrofit-2

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/ReactiveX/RxJava/issues/4942#issuecomment-269628044, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEd1vkEI5AT3Nopo_p_lyfa1_iYTkks5rM7DagaJpZM4LXi_I .

mhdtouban commented 7 years ago

am getting GaiException instead of UHE which we were normally getting in RXjava and retrofit 1. Checking instance of GaiException is not allowed leading me to check to RuntimeException which looks vacuous. https://android.googlesource.com/platform/libcore/+/5d930ca/luni/src/main/java/android/system/GaiException.java

chrjsorg commented 7 years ago

I still think we need a new version of RxJavaCallAdapterFactory for RxJava2, am I right?

naturalwarren commented 7 years ago

Just use com.squareup.retrofit2:adapter-rxjava2:2.1.0.

It's bundled in the retrofit-adapters module of retrofit.

chrjsorg commented 7 years ago

I see. But its not finally released: https://github.com/square/retrofit/issues/2151

Thanks anyway.

lucas34 commented 7 years ago

You can use 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'

ianomad commented 7 years ago

@lucas34 to be precise, it is 2.2.0 com.jakewharton.retrofit:retrofit2-rxjava2-adapter:2.2.0

eGorets commented 7 years ago

@ianomad Error:Could not find com.jakewharton.retrofit:retrofit2-rxjava2-adapter:2.2.0. Was it deployed into repo?

JakeWharton commented 7 years ago

Use 2.3.0

On Thu, Jun 8, 2017 at 11:53 AM eGorets notifications@github.com wrote:

@ianomad https://github.com/ianomad Error:Could not find com.jakewharton.retrofit:retrofit2-rxjava2-adapter:2.2.0. Was it deployed into repo?

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/ReactiveX/RxJava/issues/4942#issuecomment-307146355, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEdYQA9y18kuiKPM31EJQZKd9NU-Eks5sCBjzgaJpZM4LXi_I .

eGorets commented 7 years ago

@JakeWharton the same issue There is my list of dependencies:

compile 'com.squareup.retrofit2:adapter-rxjava:2.3.0'
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.0.0'

compile 'com.squareup.okhttp3:okhttp:3.8.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.8.0'

compile 'com.trello.rxlifecycle2:rxlifecycle:2.0.1'
compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.0.1'`

But my main issue is -- when start internet request with no internet connection, I can't handle this error and app crashes.

06-08 11:46:16.670 io.cex.app.dev.debug W/System.err: java.net.UnknownHostException: Unable to resolve host "dev.chain.com": No address associated with hostname
06-08 11:46:16.690 io.cex.app.dev.debug W/System.err:     at java.net.InetAddress.lookupHostByName(InetAddress.java:457)
06-08 11:46:16.690 io.cex.app.dev.debug W/System.err:     at java.net.InetAddress.getAllByNameImpl(InetAddress.java:252)
06-08 11:46:16.690 io.cex.app.dev.debug W/System.err:     at java.net.InetAddress.getAllByName(InetAddress.java:215)
06-08 11:46:16.690 io.cex.app.dev.debug W/System.err:     at okhttp3.Dns$1.lookup(Dns.java:39)
06-08 11:46:16.690 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.connection.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:171)
06-08 11:46:16.690 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.java:137)
06-08 11:46:16.690 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.connection.RouteSelector.next(RouteSelector.java:82)
06-08 11:46:16.690 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:171)
06-08 11:46:16.690 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:121)
06-08 11:46:16.690 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:100)
06-08 11:46:16.691 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
06-08 11:46:16.691 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
06-08 11:46:16.691 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
06-08 11:46:16.691 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
06-08 11:46:16.691 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
06-08 11:46:16.691 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
06-08 11:46:16.692 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
06-08 11:46:16.692 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
06-08 11:46:16.692 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
06-08 11:46:16.692 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
06-08 11:46:16.692 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
06-08 11:46:16.692 io.cex.app.dev.debug W/System.err:     at com.ihsanbal.logging.LoggingInterceptor.intercept(LoggingInterceptor.java:56)
06-08 11:46:16.692 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
06-08 11:46:16.692 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
06-08 11:46:16.692 io.cex.app.dev.debug W/System.err:     at com.readystatesoftware.chuck.ChuckInterceptor.intercept(ChuckInterceptor.java:172)
06-08 11:46:16.692 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
06-08 11:46:16.692 io.cex.app.dev.debug W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
06-08 11:46:16.692 io.cex.app.dev.debug W/System.err:     at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:185)
06-08 11:46:16.692 io.cex.app.dev.debug W/System.err:     at okhttp3.RealCall.execute(RealCall.java:69)
06-08 11:46:16.692 io.cex.app.dev.debug W/System.err:     at retrofit2.OkHttpCall.execute(OkHttpCall.java:180)
06-08 11:46:16.693 io.cex.app.dev.debug W/System.err:     at com.jakewharton.retrofit2.adapter.rxjava2.CallObservable.subscribeActual(CallObservable.java:41)
06-08 11:46:16.693 io.cex.app.dev.debug W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10179)
06-08 11:46:16.693 io.cex.app.dev.debug W/System.err:     at com.jakewharton.retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:34)
06-08 11:46:16.693 io.cex.app.dev.debug W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10179)
06-08 11:46:16.693 io.cex.app.dev.debug W/System.err:     at io.reactivex.internal.operators.observable.ObservableMap.subscribeActual(ObservableMap.java:32)
06-08 11:46:16.693 io.cex.app.dev.debug W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10179)
06-08 11:46:16.693 io.cex.app.dev.debug W/System.err:     at io.reactivex.internal.operators.observable.ObservableDoOnEach.subscribeActual(ObservableDoOnEach.java:42)
06-08 11:46:16.693 io.cex.app.dev.debug W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10179)
06-08 11:46:16.693 io.cex.app.dev.debug W/System.err:     at io.reactivex.internal.operators.observable.ObservableDoOnEach.subscribeActual(ObservableDoOnEach.java:42)
06-08 11:46:16.693 io.cex.app.dev.debug W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10179)
06-08 11:46:16.693 io.cex.app.dev.debug W/System.err:     at io.reactivex.internal.operators.observable.ObservableSubscribeOn$1.run(ObservableSubscribeOn.java:39)
06-08 11:46:16.693 io.cex.app.dev.debug W/System.err:     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
06-08 11:46:16.693 io.cex.app.dev.debug W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
06-08 11:46:16.693 io.cex.app.dev.debug W/System.err:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
06-08 11:46:16.693 io.cex.app.dev.debug W/System.err:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
06-08 11:46:16.693 io.cex.app.dev.debug W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
06-08 11:46:16.694 io.cex.app.dev.debug W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
06-08 11:46:16.694 io.cex.app.dev.debug W/System.err:     at java.lang.Thread.run(Thread.java:818)
06-08 11:46:16.694 io.cex.app.dev.debug W/System.err: Caused by: android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
06-08 11:46:16.696 io.cex.app.dev.debug W/System.err:     at libcore.io.Posix.android_getaddrinfo(Native Method)
06-08 11:46:16.696 io.cex.app.dev.debug W/System.err:     at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:55)
06-08 11:46:16.696 io.cex.app.dev.debug W/System.err:     at java.net.InetAddress.lookupHostByName(InetAddress.java:438)
06-08 11:46:16.696 io.cex.app.dev.debug W/System.err:   ... 47 more
06-08 11:46:17.536 io.cex.app.dev.debug E/AndroidRuntime: FATAL EXCEPTION: main
                                                          Process: io.cex.app.dev.debug, PID: 4419
eGorets commented 7 years ago

@JakeWharton thanks you pull me to the right direction, I set right dependencies, but it didn't help me to solve main issue, I'll create separate ticket

daliyan commented 7 years ago

@JakeWharton the same issue


 "rxjava"                   : "io.reactivex.rxjava2:rxjava:2.0.5",
 "rxandroid"                : "io.reactivex.rxjava2:rxandroid:2.0.1",
  converter-gson"           : "com.squareup.retrofit2:converter-gson:2.1.0",
  "retrofit2-rxjava2-adapter": "com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0",

no internet connection, repeated requests with exception

java.io.IOException: java.net.UnknownHostException: Unable to resolve host "url": No address associated with hostname
    at com.xxx.core.http.interceptor.strategy.RequestStrategy.request(RequestStrategy.java:53)
            06-09 13:00:43.786 6602-8305/com.xxx E/CrashReport: ║   at com.xxx.core.http.interceptor.CacheInterceptor.intercept(CacheInterceptor.java:57)
            06-09 13:00:43.786 6602-8305/com.xxx E/CrashReport: ║   at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
            06-09 13:00:43.786 6602-8305/com.xxx E/CrashReport: ║   at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
            06-09 13:00:43.786 6602-8305/com.xxx E/CrashReport: ║   at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:185)
            06-09 13:00:43.786 6602-8305/com.xxx E/CrashReport: ║   at okhttp3.RealCall.execute(RealCall.java:69)
            06-09 13:00:43.786 6602-8305/com.xxx E/CrashReport: ║   at retrofit2.OkHttpCall.execute(OkHttpCall.java:174)
            06-09 13:00:43.786 6602-8305/com.xxx E/CrashReport: ║   at com.jakewharton.retrofit2.adapter.rxjava2.CallObservable.subscribeActual(CallObservable.java:41)
            06-09 13:00:43.786 6602-8305/com.xxx E/CrashReport: ║   at io.reactivex.Observable.subscribe(Observable.java:10685)
            06-09 13:00:43.786 6602-8305/com.xxx E/CrashReport: ║   at io.reactivex.internal.operators.observable.ObservableSubscribeOn$1.run(ObservableSubscribeOn.java:39)
            06-09 13:00:43.786 6602-8305/com.xxx E/CrashReport: ║   at io.reactivex.Scheduler$1.run(Scheduler.java:134)
            06-09 13:00:43.786 6602-8305/com.xxx E/CrashReport: ║   at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:59)
            06-09 13:00:43.786 6602-8305/com.xxx E/CrashReport: ║   at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:51)
            06-09 13:00:43.786 6602-8305/com.xxx E/CrashReport: ║   at java.util.concurrent.FutureTask.run(FutureTask.java:237)
            06-09 13:00:43.786 6602-8305/com.xxx E/CrashReport: ║   at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
            06-09 13:00:43.786 6602-8305/com.xxx E/CrashReport: ║   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
            06-09 13:00:43.786 6602-8305/com.xxx E/CrashReport: ║   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
            06-09 13:00:43.787 6602-8305/com.xxx E/CrashReport: ║   at java.lang.Thread.run(Thread.java:761)

I can't handle this error and app crashes.

Jcdroid commented 7 years ago
Interceptor cacheInterceptor = new Interceptor() {...};

// don't use addNetworkInterceptor to add cacheInterceptor
new OkHttpClient.Builder().addNetworkInterceptor(cacheInterceptor).build();

// change addNetworkInterceptor into addInterceptor
new OkHttpClient.Builder().addInterceptor(cacheInterceptor).build();
LynnO commented 7 years ago

@chrjsorg import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; Were you looking for this?

gunjitdhawan commented 6 years ago

Did anyone solve this problem? I'm having same problem as @daliyan

jonneymendoza commented 6 years ago

I too am having same problem. any suggestions?

zouzhenglu commented 6 years ago

I am using rx 2.0.0 and retrofit 2.3.0,It still have this problem. Did anyone solve this problem?

erlangparasu commented 6 years ago

Same here. need help

akarnokd commented 6 years ago

@erlangp RxJava 2 doesn't do networking or signal such exception so it is up to Retrofit or the adapter what it signals. I suggest asking this on Stackoverflow instead.

gunjitdhawan commented 6 years ago

Add this statement to Application class

RxJavaPlugins.setErrorHandler(new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {

            }
        });
Zhuinden commented 6 years ago

This is because RxJava2Adapter creates a call that is not deferred at all, it is executed immediately upon subscription, so it goes to onError at the very first step and you'll receive UnknownHostException immediately on subscribing.

I wanted to add a valve to ensure RxJava singles run only if there is network availability, for this I had to clone out RxJava2Adapter and add some hacky code:

    @Override
    public Object adapt(@NonNull final Call<R> call) {
        Observable<Response<R>> responseObservable = isAsync
                ? new CallEnqueueObservable<>(call)
                : RxUtilsKt.valve(
                Single.just("").toFlowable(),
                App.INSTANCE.getNetworkAvailability()
                        .observeOn(Schedulers.io())) // <-- important!
                .toObservable()
                .flatMap(new Function<String, ObservableSource<Response<R>>>() {
                    @Override
                    public ObservableSource<Response<R>> apply(String ignored) {
                        return new CallExecuteObservable<>(call);
                    }
                });

It works though so I'm currently happy with it.


Theoretically to solve you guys' problem, it would need to be wrapped in Observable.defer.

    Observable<Response<R>> responseObservable = isAsync
                ? new CallEnqueueObservable<>(call)
                : Observable.defer(new Callable<ObservableSource<? extends Response<R>>>() {
            @Override
            public ObservableSource<? extends Response<R>> call() throws Exception {
                return new CallExecuteObservable<>(call);
            }
        });

I think. I'm not sure. But someone can try it.