Retrofit + RxJava 业务状态重定向及分离

问题

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

  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 == 2xx,表示业务成功。其他表示业务失败,codeMsg 更详细地描述业务状态信息。例如:

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

实现

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

/**
 * CommonResponse - 通用类
 * 泛型 T 可以为 List , 也可以是 Object , 也可以为空。
 */
public class CommonResponse {
    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>() {
            @Override
            public Subscriber> call(final Subscriber subscriber) {
                return new Subscriber>() {
                    @Override
                    public void onCompleted() {
                        subscriber.onCompleted();
                    }

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

                    @Override
                    public void onNext(CommonResponse tCommonResponse) {

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

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

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

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

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

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

/**
 * 这里为了示例,简化了Retrofit Service、Api 创建的过程。 
 */
JKApi mApi = JKService.createJKService();
mApi.getWeatherForCity("北京")
    .compose(new RedirectResponseTransformer())
    .subscribe(new Subscriber() {
                    @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 等。以后将不断完善。

你可能感兴趣的:(Retrofit + RxJava 业务状态重定向及分离)