【问题标题】:Retrofit2 + RxJava error handlingRetrofit2 + RxJava 错误处理
【发布时间】:2017-01-20 03:43:42
【问题描述】:

我正在使用 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。任何人都可以验证这是真的吗?

【问题讨论】:

    标签: android retrofit rx-java retrofit2 okhttp3


    【解决方案1】:

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

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

    如果您的 onComplete() 中有异常,RxJava 将传播 rx.exceptions.OnCompletedFailedException,如果 onError() 中有异常 - 您将获得 rx.exceptions.OnErrorFailedException

    也就是说,您可以只探测您在 onError() 方法中收到的 Throwable 以查找您所期望的异常。例如,您知道如果您的 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();
    }
    

    【讨论】:

      【解决方案2】:

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

      错误 HTTP 代码是有效响应,您不应在 onError 中处理它们。 您可以将 Retrofit 服务的返回类型包装在 Result 中,这样您就可以在不引发异常的情况下获取有关调用所发生情况的信息。

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

          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 来处理我可能错过的一些事情。这是非常个人化的,但我更喜欢快速崩溃,而不是处于未知状态一段时间,以后会出现更难调试的崩溃。

      【讨论】:

        【解决方案3】:

        在 Kotlin 中,我使用了 bellow like..

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-12-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多