简体   繁体   English

Retrofit2 + RxJava 错误处理

[英]Retrofit2 + RxJava error handling

I am using RxJava and Retrofit2 (with OkHttp as the HTTP client) to do networking and am trying to understand how different errors are handled by Retrofit2 and how they look from the RxJava side.我正在使用 RxJava 和 Retrofit2(以 OkHttp 作为 HTTP 客户端)进行网络连接,并试图了解 Retrofit2 如何处理不同的错误以及它们从 RxJava 方面的外观。 The following code illustrates an RxJava Subscriber callback for a network call (made with Retrofit).以下代码说明了网络调用的 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();
                }
            });

My question is, in what cases will onError() be called and once it's been called, how can I interrogate the Throwable to determine the cause?我的问题是,在什么情况下会调用 onError() 并且一旦被调用,我如何查询 Throwable 以确定原因?

From the Retrofit source it looks like the only Throwables that are possible to see are IOException and HttpException.从 Retrofit 源代码看来,唯一可以看到的 Throwables 是 IOException 和 HttpException。 Can anyone verify that that is true?任何人都可以验证这是真的吗?

Here's the basics: onError() will be called if:这是基础知识: onError()将在以下情况下被调用:

  • the observable you're subscribing to throws an exception (eg you get an IOException while trying to read a file)您订阅的observable抛出异常(例如,您在尝试读取文件时收到IOException
  • an exception is raised in your onNext() method.在您的onNext()方法中引发异常。

If there's an exception in your onComplete() , RxJava will propagate an rx.exceptions.OnCompletedFailedException and if there's an exception in onError() - you'll get rx.exceptions.OnErrorFailedException .如果您的onComplete()有异常, RxJava将传播rx.exceptions.OnCompletedFailedException并且如果onError()有异常 - 您将得到rx.exceptions.OnErrorFailedException

That said, you can just probe the Throwable you receive in your onError() method for exceptions that you're expecting.也就是说,您可以只探测在onError()方法中收到的Throwable是否有您期望的异常。 For example you know that if your API call results in client error (4xx), Retrofit will wrap it into HttpException .例如,您知道如果您的 API 调用导致客户端错误 (4xx),Retrofit 会将其包装到HttpException If there's a timeout with the request you'll get a SocketTimeoutException .如果请求超时,您将收到SocketTimeoutException Here's a rough example:这是一个粗略的例子:

@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();
}

Do not use onError for flow.不要将onError用于流。 That'd be as bad as try-catch for flow.这和try-catch for flow 一样糟糕。

Error HTTP codes, are valid responses and you should not deal with them in onError .错误 HTTP 代码是有效的响应,您不应在onError处理它们。 You can wrap the return type of your Retrofit services in Result , that gives you the means to get information about what happen with your call without throwing exceptions.您可以将 Retrofit 服务的返回类型包装在Result ,这使您可以在不抛出异常的情况下获取有关调用发生的情况的信息。

You can handle the state of your app using this pattern:您可以使用此模式处理应用程序的状态:

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

See how I tried to handle all possible states within the stream and deliberately I throw OnErrorNotImplementedException for something I might've missed.看看我如何尝试处理流中所有可能的状态,并故意抛出OnErrorNotImplementedException来解决我可能错过的一些事情。 This is very personal but I prefer to crash-fast-and-furious rather than being in an unknown state for a while that later will manifest in a crash harder to debug.这是非常个人化的,但我更喜欢快速崩溃,而不是在一段时间内处于未知状态,稍后会在更难调试的崩溃中表现出来。

In Kotlin I have used bellow like..在 Kotlin 中,我使用了 bellow 之类的。

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


            }

        })
    )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM