问题

本文主要介绍了在 Retrofit + RxJava 环境下更优雅的解决了以下两个问题:

  1. 将接口业务上的失败重定向到 onError(Throwable e) 输出;
  2. 业务成功时分离出 data 数据由 onNext(T t) 输出;

场景

一般来说,一个友好的接口返回 json 应该是这样的:

{
"code":200,
"codeMsg":"查询成功!",
"data":{
"city":"北京",
"temperature":"8℃~20℃",
"weather":"晴转霾"}
}

或者这样的:

{
"code":200,
"codeMsg":"查询成功!",
"data":[
{
"city":"北京",
"temperature":"8℃~20℃",
"weather":"晴转霾"},
{
"city":"南京",
"temperature":"12℃~21℃",
"weather":"晴"}
]
}

如果约定好,code == 200,表示业务成功。其他表示业务失败,codeMsg 更详细地描述业务状态信息。例如:

{
"code":"400",
"codeMsg":"未知的城市"}

实现

要知道,利用 Retrofit + Gson (或者其他 Converter ) 可以将返回的 Json 的转换为对象的,那么可以定义以下返回通用类 Model :

/**
* CommonResponse - 通用类
* 泛型 T 可以为 List<object> , 也可以是 Object , 也可以为空。
*/
public class CommonResponse<T> {
private int code;
private String codeMsg;
private T data;

public int getCode() {
return code;
}

public String getCodeMsg() {
return codeMsg;
}

public T getData() {
return data;
}

/**
* 根据 code 码判断业务状态
* code == 2xx,表示业务成功。其他表示业务失败,codeMsg 进一步描述业务状态。
*/
public boolean isSuccess() {
return code / 100 == 2;
}
}

为了解决上面提出的两个问题,这里可以使用 RxJava 中的 lift() 来自定义操作:

/**
* 这里为了示例,简化了Retrofit Service、Api 创建的过程。
*/
JKApi mApi = JKService.createJKService();
mApi.getWeatherForCity("北京").lift(new Observable.Operator<T, CommonResponse<T>>() {
@Override
public Subscriber<? super CommonResponse<T>> call(final Subscriber<? super T> subscriber) {
return new Subscriber<CommonResponse<T>>() {
@Override
public void onCompleted() {
subscriber.onCompleted();
}

@Override
public void onError(Throwable e) {
subscriber.onError(e);
}

@Override
public void onNext(CommonResponse<T> tCommonResponse) {

if (tCommonResponse.isSuccess())
subscriber.onNext(tCommonResponse.getData());
else
subscriber.onError(new

上面的 lift() 操作想要对每一个符合这样标准的接口都通用,并且顺便对线程指定进行封装。可以 implements Observable.Transformer

public class RedirectResponseTransformer<T> implements Observable.Transformer<CommonResponse<T>, T> {
@Override
public Observable<T> call(
Observable<CommonResponse<T>> CommonResponseObservable) {
return CommonResponseObservable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.lift(new Observable.Operator<T, CommonResponse<T>>() {
@Override
public Subscriber<?super CommonResponse<T>> call(
final Subscriber<?super T> subscriber) {
return new Subscriber<CommonResponse<T>>() {
@Override
public void onCompleted() {
subscriber.onCompleted();
}

@Override
public void onError(Throwable e) {
subscriber.onError(e);
}

@Override
public void onNext(
CommonResponse<T> tCommonResponse) {
if (tCommonResponse.isSuccess()) {
subscriber.onNext(tCommonResponse.getData());
} else {
subscriber.onError(new

最后我们使用 Observable.compose(Transformer transformer) 方法将以上的封装加入到 Rx-Chain 中去:

/**
* 这里为了示例,简化了Retrofit Service、Api 创建的过程。
*/
JKApi mApi = JKService.createJKService();
mApi.getWeatherForCity("北京")
.compose(new RedirectResponseTransformer<WeatherModel>())
.subscribe(new Subscriber<WeatherModel>() {
@Override
public void onCompleted() {

}

@Override
public void onError(Throwable e) {
showShortToast(e.toString());
}

@Override
public void onNext(WeatherModel weatherModel) {
// do something like refresh ui

到这里,针对上文提出的两个问题已经做了封装。其实利用 RxJava 强大的运算符还可以做很多封装。例如:针对特定异常显示Toast、onComplete() 回调中 dismiss loadingDialog 等。