改造2.0 + RxJava +错误JSON正文

时间:2015-11-28 23:32:14

标签: android json retrofit rx-java

我是RxJava和Retrofit的新手,我正在尝试用它编写我的API调用。所有API调用都会返回错误的JSON正文,其格式为

#each block

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

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

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

2 个答案:

答案 0 :(得分:6)

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

  <android.support.v7.widget.CardView> // pseudocode to show container
  <RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <com.android.volley.toolbox.NetworkImageView
        android:id="@+id/event_photo"
        android:scaleType="centerCrop"
        android:transitionName="eventImage"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:layout_alignParentTop="true"
       />
    <TextView
        android:id="@+id/event_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/event_photo"
        android:text="Title"
        android:transitionName="eventTitle"/>
    <TextView
        android:id="@+id/event_date"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/event_title"
        android:text="Date"/>
    <TextView
        android:id="@+id/event_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Time"
        android:layout_below="@id/event_date"/>


    <TextView
        android:id="@+id/event_price"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="£ FREE" />
    <TextView
        android:id="@+id/event_organ"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:layout_above="@id/event_price"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    </RelativeLayout>
</android.support.v7.widget.CardView>

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

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

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

答案 1 :(得分:0)

反序列化也可能是一个问题。您可以使用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
}