我是RxJava和Retrofit的新手,我正在尝试用它编写我的API调用。所有API调用都会返回错误的JSON正文,其格式为
#each block
目前我的登录API调用代码(其他也类似)是,
{"errors":[{"code":100, "message":"Login/Password not valid", "arguments":null}]}
当我在onError()上收到错误时,我想自动将错误正文中的JSON解码为POJO并使用它。有没有办法在一个地方为所有其他API调用执行此操作。任何帮助表示赞赏。
答案 0 :(得分:6)
我建议使用可重用的Transformer和onErrorResumeNext运算符来封装你的逻辑。它看起来像这样:
<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
}