Retrofit2 + RxJava错误处理

时间:2016-09-12 16:26:29

标签: android retrofit rx-java retrofit2 okhttp3

我正在使用RxJava和Retrofit2(使用OkHttp作为HTTP客户端)进行网络连接,并试图了解Retrofit2如何处理不同的错误以及它们从RxJava方面的外观。以下代码说明了网络调用的RxJava订阅者回调(使用Retrofit进行)。

        Subscription subscription = observable
            .subscribeOn(mScheduler)
            .observeOn(mAndroidScheduler)
            .subscribe(new Subscriber<User>() {
                @Override
                public void onCompleted() {
                    Timber.d("onCompleted called");
                    mRetainerView.clearUserObservable();
                    mActivityView.hideProgressBar();
                    mActivityView.enableUi();
                }

                @Override
                public void onError(Throwable e) {
                    Timber.d("onError called");
                    Timber.d(e.toString());
                    mRetainerView.clearUserObservable();
                    mActivityView.hideProgressBar();
                    mActivityView.enableUi();
                }

                @Override
                public void onNext(User user) {
                    Timber.d("onNext called");
                    mRetainerView.clearUserObservable();
                    mActivityView.hideProgressBar();
                    mActivityView.enableUi();
                    mActivityView.launchMainActivity();
                }
            });

我的问题是,在什么情况下会调用onError(),一旦调用它,我如何查询Throwable以确定原因?

从Retrofit源看,可能看到的唯一Throwable是IOException和HttpException。任何人都可以验证这是真的吗?

3 个答案:

答案 0 :(得分:8)

以下是基础知识:onError()将在以下情况下调用:

  • 您订阅的observable会引发异常(例如,您在尝试阅读文件时获得IOException
  • 您的onNext()方法引发了异常。

如果onComplete()中存在例外情况,则RxJava会传播rx.exceptions.OnCompletedFailedException,如果onError()中存在例外情况,您将获得rx.exceptions.OnErrorFailedException

也就是说,您可以在Throwable方法中探测您收到的onError()您遇到的异常情况。例如,您知道如果您的API调用导致客户端错误(4xx),则Retrofit会将其包装到HttpException中。如果请求超时,您将获得SocketTimeoutException。这是一个粗略的例子:

@Override
public void onError(Throwable e) {
    Timber.d("onError called");
    Timber.d(e.toString());
    handleError(e);
}

private handleError(Throwable throwable) {
    if (throwable instanceof HttpException) {
        HttpException httpException = (HttpException)throwable;
        int statusCode = httpException.code();
        // handle different HTTP error codes here (4xx)
    } else if (throwable instanceof SocketTimeoutException) {
        // handle timeout from Retrofit
    } else if (throwable instanceof IOException) {
       // file was not found, do something
    } else {
       // generic error handling
       mRetainerView.clearUserObservable();
       mActivityView.hideProgressBar();
       mActivityView.enableUi();
}

答案 1 :(得分:0)

不要将onError用于流量。这与流量try-catch一样糟糕。

错误HTTP代码是有效的回复,您不应在onError中处理它们。 您可以在Result中包装Retrofit服务的返回类型,这样您就可以获得有关调用的信息而不会抛出异常的信息。

您可以使用以下模式处理应用的状态:

    service.getSomething()
        .map(r -> Model.success(r.response()))
        .onErrorReturn(Model::error)
        .observeOn(AndroidSchedulers.mainThread())
        .startWith(Resource.loading())
        .subscribe(r -> {
            myProgressBar.setVisible(r.isLoading());
            if (r.isSuccess()) {
                handleSuccess(); // e.g. 400 is also success but needs handling
            }
            if (r.isError()) {
                handleError();
            }
        }, OnErrorNotImplementedException::new);

了解我是如何尝试处理流中的所有可能状态的,并故意将OnErrorNotImplementedException扔给我可能已经错过的内容。这是非常个人化的,但我喜欢速度快而且速度快,而不是暂时处于未知状态,之后将在崩溃中表现得更难调试。

答案 2 :(得分:0)

在科特林,我用过类似波纹管的东西。

disposable.add(apiService.getLogin_service(parment1,parment1)
        .subscribeOn(Schedulers.newThread())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribeWith(object : DisposableSingleObserver<Login_Reg_Data_Model>() {
            override fun onSuccess(model: Login_Reg_Data_Model) {
               //success
            }

            override fun onError(e: Throwable) {  


                if (e is HttpException) {
                    // We had non-200 http error
                    Log.e("time exceptionr******>",e.message)
                } else if (e is SocketTimeoutException) {
                    //time exception
                    Log.e("time exception******>",e.message)
                } else if (e is IOException) {
                    // A network error
                    Log.e("network error******>",e.message)
                } else {
                    //unknown error
                    Log.e("unknown error******>",e.message)
                }


            }

        })
    )