1. 程式人生 > >RxJava2 + Retrofit2 處理data為null的情況

RxJava2 + Retrofit2 處理data為null的情況

最近專案中使用了RxJava2+ Retrofit2框架,框架基本都是統一封裝HttpBean,使用map操作符轉化資料,然後根據code碼的邏輯去處理業務,開發過程中遇到一個問題,伺服器返回的json資料格式為{"code": 200, "data": null, "message": null}, 發現客戶端竟然報錯解析不了。。。

附上之前寫的程式碼:

public class RxFunction<T> implements Function<BaseHttpBean<T>, T> {

    @Override
    public T apply(BaseHttpBean<T> httpBean) throws Exception {
        String resultCode = httpBean.getCode();
        if (!HttpCode.SUCCESS.equals(resultCode)) {
            throw new ApiException(resultCode, httpBean.getMessage());
        }
        return httpBean.getData();
    }

}

網上百度了一下是說RxJava2之後map操作符就不允許傳送一個null從上游交給下游了。那可怎麼辦哪,那時候天真的以為不要讓伺服器返回data為null的資料就好了,搞得後臺的人一臉懵逼~ 哈哈 。

最後從這篇文章裡借鑑了思路,解決了問題。https://www.jianshu.com/p/f1957c9c2240

首先新寫一個類:Optional, 這個是Java8新出的特性。是為了解決null安全問題出的API(核心)

public class Optional<M> {

    private final M optional; // 接收到的返回結果

    public Optional(@Nullable M optional) {
        this.optional = optional;
    }

    // 判斷返回結果是否為null
    public boolean isEmpty() {
        return this.optional == null;
    }

    // 獲取不能為null的返回結果,如果為null,直接拋異常,經過二次封裝之後,這個異常最終可以在走向RxJava的onError()
    public M get() {
        if (optional == null) {
            throw new NoSuchElementException("No value present");
        }
        return optional;
    }

    // 獲取可以為null的返回結果
    public M getIncludeNull() {
        return optional;
    }
}

接下來把泛型T使用Optinal包裝一下。

public class RxTransformer {

    public static <T> ObservableTransformer<BaseHttpBean<T>, Optional<T>> handle_result() {
        return upstream -> upstream
                .flatMap(new Function<BaseHttpBean<T>, ObservableSource<Optional<T>>>() {
                             @Override
                             public ObservableSource<Optional<T>> apply(@NonNull BaseHttpBean<T> result) throws Exception {
                                 if (HttpCode.SUCCESS.equals(result.getCode())) {
                                     // result.transform() 就是將返回結果進行包裝
                                     return createHttpData(result.transform());
                                 } else {
                                     // 傳送請求失敗的資訊
                                     return Observable.error(new ApiException(result.getCode(), result.getMessage()));
                                 }

                                 return Observable.empty();
                             }
                         }
                );
    }

    public static <T> Observable<Optional<T>> createHttpData(Optional<T> t) {

        return Observable.create(e -> {
            try {
                e.onNext(t);
                e.onComplete();
            } catch (Exception exc) {
                e.onError(exc);
            }
        });
    }

}

原來的結構如下:

 public Observable<LoginBean> login(Map map) {
        return Api.getApiService()
                .requestLogin(getRequestBody(map))
                .map(new RxFunction<LoginBean>())
                .compose(RxSchedulers.io2Main());
 }

修改之後的結構如下:

    public Observable<Optional<LoginBean>> login(Map<String, Object> map) {
        return Api.getApiService()
                .requestLogin(map)
                .compose(RxTransformer.handle_result())
                .compose(RxSchedulers.io2Main());
    }

最後接收T的時候只需要取getIncludeNull()即可。注意是取getIncludeNull ,取get還是會報異常的