Retrofit2 和 RxJava 的错误处理

4

我正在使用RxJava和Retrofit2(使用OkHttp作为HTTP客户端)进行网络请求,并试图了解Retrofit2如何处理不同的错误以及它们在RxJava方面的表现。以下代码演示了一个用Retrofit进行网络请求时的RxJava Subscriber回调。

        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源代码来看,似乎可能看到的只有IOException和HttpException。有人可以验证这是正确的吗?
3个回答

10

这里是基础知识:如果发生以下情况,onError()将被调用:

  • 您订阅的observable抛出异常(例如,在尝试读取文件时遇到IOException
  • 您的onNext()方法中引发了异常。

如果onComplete()中出现异常,RxJava将传播rx.exceptions.OnCompletedFailedException,如果onError()中出现异常,则会得到rx.exceptions.OnErrorFailedException

也就是说,您可以在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
不要在流程中使用 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。这非常个人化,但我更喜欢快速而猛烈地崩溃,而不是在未知状态下停留一段时间,然后在更难调试的崩溃中表现出来。

0

在 Kotlin 中,我使用了以下代码:

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)
                }


            }

        })
    )

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接