1

Hello guys I have in my BaseActivity the following function.

override fun <T> subscribeToInternet(observable: Observable<Response<BaseResponse<T>>>, observer: Observer<BaseResponse<T>>) {
    observable.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .doOnSubscribe { observer.onSubscribe(it) }
            .doOnError {
                Log.d(TAG, it.message)
                observer.onError(it)
            }
            .doOnComplete { observer.onComplete() }
            .doOnNext {
                Log.d(TAG, "${it.body() ?: "no body"}")
                Log.d(TAG, "${it.errorBody()?.string() ?: "no error body"}")
                Log.d(TAG, it.code().toString())
                when {
                    it.code() == 401 -> {
                        view.userUnauthenticated()
                        observer.onNext(BaseResponse(false, "unauthenticated", null))
                        Log.d(TAG, "UNAUTHENTICATED")
                    }
                    it.code() == 423 -> {
                        view.userBlocked()
                        observer.onNext(BaseResponse(false, "blocked", null))
                        Log.d(TAG, "BLOCKED")
                    }
                    it.isSuccessful -> observer.onNext(it.body()!!)
                    it.code() == 429 -> observer.onNext(BaseResponse(false, "Too many attempts", null))
                    it.code() == 400 -> observer.onNext(BaseResponse(false, "Invalid Email or password", null))
                    else -> observer.onNext(BaseResponse(false, "", null))
                }
            }
            .subscribe()
}

And I handle the error in the observer's onNext() if the server returns a response, but the problem when there's no Internet connection on the device at all!! It throws the following exception

at io.reactivex.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onError(ObservableDoOnEach.java:119)
    at io.reactivex.internal.observers.DisposableLambdaObserver.onError(DisposableLambdaObserver.java:64)
    at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.checkTerminated(ObservableObserveOn.java:276)
    at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.drainNormal(ObservableObserveOn.java:172)
    at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.run(ObservableObserveOn.java:252)

And this is the usage of the previously mentioned function

override fun sendLoginRequest(email: String, password: String, fcm_token: String) {
    subscribeToInternet(dataManager.sendLoginRequest(email, password, fcm_token), this)
}

override fun onComplete() {

}

override fun onSubscribe(d: Disposable) {
    DisposableManager.add(d)
}

override fun onNext(t: BaseResponse<LoginData>) {
    if(t.status) {
        Log.d(TAG, "${t.data}")
        dataManager.createLoginSession(t.data!!)
        view.loginSuccess()
    } else {
        Log.d(TAG, t.message)
        view.showError(t.message)
    }
}

override fun onError(e: Throwable) {
    view.showToastError()
    Log.d(TAG, e.message)
}
Taha Malas
  • 23
  • 4

1 Answers1

0

That problem is connected with the way you subscribing to observable. According to documentation when using subscribe() without passing action for handling errors, you should receive OnErrorNotImplementedException when source throws exceptions - that's because default exception handler from RxJavaPlugins is used.

To resolve that problem use one of overloaded subscribe methods with onError parameter. For example, public final Disposable subscribe(Consumer onNext, Consumer onError)

ConstOrVar
  • 2,025
  • 1
  • 11
  • 14
  • Thanks for your precise response.. But isn't doOnError enough for error handling? – Taha Malas Sep 18 '18 at 21:31
  • @TahaMalas, no, it's not enough. `doOnError` only allow to trigger additional action when error happened. According to observable contract, when error happened your source will be terminated. So when you call `subscribe` with `onError` parameter, you are sure that properly handle termination of your source (in case of throwing exception). – ConstOrVar Sep 19 '18 at 06:36
  • Thank you so much it worked like a charm.. So should I move doOnNext, doOnError, doOnComplete and doOnSubscribe and pass them in the subscribe parameters? – Taha Malas Sep 20 '18 at 08:47
  • I recommend you pass you observer directly in `subscribe()` and return `Subscription` back from your method, because in some cases you should manually trigger Subscription.unsubbscribe() to free up occupied resources. And by the way, you can extract you switch/case block in `map` operator. In my opinion, it will be more Rx idiomatic. – ConstOrVar Sep 20 '18 at 11:43