【问题标题】:Retrofit 2.0 + RxJava + Error JSON body改造 2.0 + RxJava + 错误 JSON 正文
【发布时间】:2016-03-02 20:30:06
【问题描述】:

我对 RxJava 和 Retrofit 还很陌生,我正在尝试用它来编写我的 API 调用。所有 API 调用都会在错误时返回 JSON 正文,其一般格式为,

{"errors":[{"code":100, "message":"Login/Password not valid", "arguments":null}]}

目前我的登录 API 调用代码(其他也类似)是,

mConnect.login(id, password)
        .subscribe(new Subscriber<Token>() {
            @Override
            public void onCompleted() {
                Log.d(TAG, "onCompleted()");
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError(): " + e);
                if (e instanceof HttpException) {
                  // dump e.response().errorBody()
                }
            }

            @Override
            public void onNext(Token token) {
                Log.d(TAG, "onNext(): " + token);
            }
        });

当我在 onError() 中遇到错误时,我想自动将错误正文中的 JSON 解码为 POJO 并使用它。有没有办法最好在一个地方为所有其他 API 调用执行此操作。任何帮助表示赞赏。

【问题讨论】:

    标签: android json retrofit rx-java


    【解决方案1】:

    我建议使用可重用的TransformeronErrorResumeNext 运算符来封装您的逻辑。它看起来像这样:

    <T> Observable.Transformer<T, T> parseHttpErrors() {
        return new Observable.Transformer<T, T>() {
            @Override
            public Observable<T> call(Observable<T> observable) {
                return observable.onErrorResumeNext(new Func1<Throwable, Observable<? extends T>>() {
                    @Override
                    public Observable<? extends T> call(Throwable throwable) {
                        if (throwable instanceof HttpException) {
                            HttpErrorPojo errorPojo = // deserialize throwable.response().errorBody();
    
                            // Here you have two options, one is report this pojo back as error (onError() will be called),
                            return Observable.error(errorPojo); // in this case HttpErrorPojo would need to inherit from Throwable
    
                            // or report this pojo back as part of onNext()
                            return Observable.just(errorPojo); //in this case HttpErrorPojo would need to inherit from <T>
                        }
                        // if not the kind we're interested in, then just report the same error to onError()
                        return Observable.error(throwable);
                    }
                });
            }
        };
    }
    

    请注意代码中的 cmets,因为您必须决定是要报告解析后的响应 onError() 还是 onNext()。

    然后您可以在 API 调用中的任何位置使用此转换器,如下所示:

    mConnect.login(id, password)
            .compose(this.<Token>parseHttpErrors()) // <-- HERE
            .subscribe(new Subscriber<Token>() {
                @Override
                public void onCompleted() {
                    Log.d(TAG, "onCompleted()");
                }
    
                @Override
                public void onError(Throwable e) {
                    Log.e(TAG, "onError(): " + e);
                    if (e instanceof HttpErrorPojo) {
                      // this will be called if errorPojo was reported via Observable.error()
                    }
                }
    
                @Override
                public void onNext(Token token) {
                    Log.d(TAG, "onNext(): " + token);
                    if (token instanceof HttpErrorPojo) {
                      // this will be called if errorPojo was reported via Observable.just()
                    }
                }
            });
    

    【讨论】:

      【解决方案2】:

      反序列化也可能是一个问题。您可以使用retrofit converter to deserialize it(或自己动手)。

      我的解决方案在 murki 的基础上增加了一点:

      <T> Observable.Transformer<T, T> parseHttpErrors() {
              return new Observable.Transformer<T, T>() {
                  @Override
                  public Observable<T> call(Observable<T> observable) {
                      return observable.onErrorResumeNext(new Func1<Throwable, Observable<? extends T>>() {
                          @Override
                          public Observable<? extends T> call(Throwable throwable) {
                              if ( throwable instanceof HttpException ) {
                                  Retrofit retrofit = new Retrofit.Builder()
                                          .baseUrl(SERVER_URL) // write your url here
                                          .addConverterFactory(GsonConverterFactory.create())
                                          .build();
                                  Converter<ResponseBody, Error> errorConverter =
                                          retrofit.responseBodyConverter(Error.class, new Annotation[0]);
                                  // Convert the error body into our Error type.
                                  try {
                                      Error error = errorConverter.convert(((HttpException) throwable).response().errorBody());
                                      // Here you have two options, one is report this pojo back as error (onError() will be called),
                                      return Observable.error(new Throwable(error.getMessage()));
                                  }
                                  catch (Exception e2) {
                                      return Observable.error(new Throwable());
                                  }
      
                              }
                              // if not the kind we're interested in, then just report the same error to onError()
                              return Observable.error(throwable);
                          }
                      });
                  }
              };
          }
      

      然后在 onError() 处,

      @Override
      public void onError(Throwable e) {
          progressBar.setVisibility(View.GONE); // optional 
          if ( !TextUtils.isEmpty(e.getMessage()) ) {
                  // show error as you like 
                  return;
          }
          // show a default error if you wish
      }
      

      【讨论】:

        猜你喜欢
        • 2015-03-06
        • 2018-02-27
        • 1970-01-01
        • 1970-01-01
        • 2017-08-26
        • 1970-01-01
        • 2016-11-17
        • 2018-12-29
        • 2016-06-28
        相关资源
        最近更新 更多