Retrofit 使用flatmap操作符时处理错误、异常

719 阅读2分钟

在实际项目(Retrofit+RxJava 框架)中,有时需要先登录,获取 token 后再去获取用户信息,那么我们需要把登录后服务器返回的信息进行筛选过滤得到我们需要的 token,然后根据 token 获取用户信息。我们最终需要做的也就是转换数据流。

RxJava 中,具有转换数据流功能的操作符有很多,这里我们使用 flatmap 转换操作符来实现数据流的转换。

在 RESTResult 对象里,包括请求返回的状态:失败还是成功,错误码,User 对象等等,我们根据接口先定义一个返回数据 Response 实体类:

public class Response<T> extends Entity {

    public boolean isSuccess() {
        return infoCode == 1;
    }
    public boolean isTokenExpired() {
        return infoCode == -1;
    }

    public int infoCode;
    public String message;
    public int size;
    public T data;
}

逻辑处理:

  • 登录失败,直接触发 onError;
  • 登录成功,根据获得的 token 请求用户信息接口最终调用 subscribe 的 onNext 事件;

如下代码所示:

private void login(final String phone , final String password){
        APIWrapper.getInstance().login(phone, password)
                .flatMap(new Func1<Response<TokenEntity>, Observable<Response<UserInfo>>>() {
                    @Override
                    public Observable<Response<UserInfo>> call(Response<TokenEntity> response) {
                        if (response.isSuccess()) {
                            TokenEntity tokenEntity = response.data;

                            return APIWrapper.getInstance().getUserInfo(tokenEntity.token);
                        } else {
                            return Observable.error(new ApiException(response.message));
                        }
                    }
                })
                .compose(new RxHelper<Response<UserInfo>>(getString(R.string.wait_to_login_tip)).io_main(LoginActivity.this))
                .subscribe(new RxSubscriber<Response<UserInfo>>(this,USER_LOGIN) {
                    @Override
                    public void _onNext(Response<UserInfo> response) {
                        if (response.isSuccess()) {
                            UserInfo userInfo = response.data;
                            if (null != userInfo) {
                                AppApplication.getInstance().saveUserInfo(userInfo);
                            }
                            finish();
                        }
                    }

                    @Override
                    public void _onError(String msg) {
                        ToastUtils.show(LoginActivity.this, msg);
                    }
                });
    }

根据上面代码,登陆失败后的处理很关键:

if (response.isSuccess()) {
                            TokenEntity tokenEntity = response.data;

                            return APIWrapper.getInstance().getUserInfo(tokenEntity.token);
                        } else {
                            return Observable.error(new ApiException(response.message));

无论何种原因造成的登陆失败,都应跟用户提示。

ApiException 代码:

public class ApiException extends RuntimeException {

    public static final int USER_NOT_EXIST = 100;
    public static final int WRONG_PASSWORD = 101;
    public static final int ERROR = 2001;

    public ApiException(int resultCode) {
        this(getApiExceptionMessage(resultCode));
    }

    public ApiException(String detailMessage) {
        super(detailMessage);
    }

    /**
     * 由于服务器传递过来的错误信息直接给用户看的话,用户未必能够理解
     * 需要根据错误码对错误信息进行一个转换,在显示给用户
     * @param code
     * @return
     */
    private static String getApiExceptionMessage(int code){
        String message ;
        switch (code) {
            case USER_NOT_EXIST:
                message = "该用户不存在";
                break;
            case WRONG_PASSWORD:
                message = "密码错误";
                break;
            default:
                message = "未知错误";

        }
        return message;
    }

}


通过 RxJava 的链式操作,结合恰当的操作符,不仅可以把正常的数据源发射给观察者,同时也可以将错误异常数据源发射给观察者,RxJava 比想象中的更强大!

更多参考:Retrofit+RxJava 优雅的处理服务器返回异常、错误