RxJava2 + Retrofit2 處理data為null的情況
阿新 • • 發佈:2018-12-15
最近專案中使用了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還是會報異常的