RxJava2 + Retrofit2 優雅簡潔封裝
RxJava2 封裝主要變化
- Transformer的變化:RxJava1.X為rx.Observable.Transformer接口, 繼承自Func1<Observable<T>, Observable<R>>, RxJava2.X為io.reactivex.ObservableTransformer<Upstream, Downstream>,是一個獨立的接口。
- Flowable則是FlowableTransformer,如果你使用Flowable,以下ObservableTransformer替換FlowableTransformer即可。
RxJava2 + Retrofit2.jpg
封裝方案
1、封裝 Rx 線程相關
RxSchedulersHelper:
/**
- Created by weiss on 17/1/16.
*/
public class RxSchedulers {
public static <T> ObservableTransformer<T, T> io_main() {
return upstream ->
upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
}</code></pre>
封裝后:
Api.getInstance().movieService
.getGankData("Android",1)
.compose(RxSchedulers.io_main());</code></pre>
2、封裝 處理服務器返回數據,管理 RxJava生命周期
HttpResult:
/**
- Created by Weiss on 2017/1/11.
*/
public class HttpResult<T> implements Serializable {
public String code;
public String msg;
public boolean hasmore;
public T data;
public static String SUCCESS = "000";
public static String SIGN_OUT = "101";//token驗證失敗
public static String SHOWTOAST = "102";//顯示Toast
public boolean isSuccess() {
return SUCCESS.equals(code);
}
public boolean isTokenInvalid() {
return SIGN_OUT.equals(code);
}
public boolean isShowToast() {
return SHOWTOAST.equals(code);
}
public boolean hasMore() {
return hasmore;
}
}</code></pre>
BaseRxActivity:
/**
- 管理RxJava生命周期,避免內存泄漏
- RxJava處理服務器返回
*
- Created by Weiss on 2016/12/23.
*/
public abstract class BaseRxActivity extends BaseActivity {
private CompositeDisposable disposables2Stop;// 管理Stop取消訂閱者者
private CompositeDisposable disposables2Destroy;// 管理Destroy取消訂閱者者
protected abstract int getLayoutId();
protected abstract void initView();
/**
* Rx優雅處理服務器返回
*
* @param <T>
* @return
*/
public <T> ObservableTransformer<HttpResult<T>, T> handleResult() {
return upstream ->{
return upstream.flatMap(result -> {
if (result.isSuccess()) {
return createData(result.data);
} else if (result.isTokenInvalid()) {
//處理token失效,tokenInvalid方法在BaseActivity 實現
tokenInvalid();
} else {
return Observable.error(new Exception(result.msg));
}
return Observable.empty();
}
);
};
}
private <T> Observable<T> createData(final T t) {
return Observable.create(subscriber -> {
try {
subscriber.onNext(t);
subscriber.onComplete();
} catch (Exception e) {
subscriber.onError(e);
}
});
}
public boolean addRxStop(Disposable disposable) {
if (disposables2Stop == null) {
throw new IllegalStateException(
"addUtilStop should be called between onStart and onStop");
}
disposables2Stop.add(disposable);
return true;
}
public boolean addRxDestroy(Disposable disposable) {
if (disposables2Destroy == null) {
throw new IllegalStateException(
"addUtilDestroy should be called between onCreate and onDestroy");
}
disposables2Destroy.add(disposable);
return true;
}
public void remove(Disposable disposable) {
if (disposables2Stop == null && disposables2Destroy == null) {
throw new IllegalStateException("remove should not be called after onDestroy");
}
if (disposables2Stop != null) {
disposables2Stop.remove(disposable);
}
if (disposables2Destroy != null) {
disposables2Destroy.remove(disposable);
}
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (disposables2Destroy != null) {
throw new IllegalStateException("onCreate called multiple times");
}
disposables2Destroy = new CompositeDisposable();
}
public void onStart() {
super.onStart();
if (disposables2Stop != null) {
throw new IllegalStateException("onStart called multiple times");
}
disposables2Stop = new CompositeDisposable();
}
public void onStop() {
super.onStop();
if (disposables2Stop == null) {
throw new IllegalStateException("onStop called multiple times or onStart not called");
}
disposables2Stop.dispose();
disposables2Stop = null;
}
public void onDestroy() {
super.onDestroy();
if (disposables2Destroy == null) {
throw new IllegalStateException(
"onDestroy called multiple times or onCreate not called");
}
disposables2Destroy.dispose();
disposables2Destroy = null;
}
}</code></pre>
封裝后 (BaseRxActivity的子類使用):
addRxDestroy(Api.getInstance().movieService
.getGankData("Android",1)
.compose(RxSchedulers.io_main())
.compose(handleResult())
.省略
);
handleResult為什么不新建一個類處理呢?因為很多異常處理需要context對象,或者和BaseActivity有千絲萬縷的聯系,BaseRxActivity繼承BaseActivity可以很簡潔優雅處理各種異常。比如token失效,是需要跳轉到登錄頁面的。在新建一個類中,不能持有context對象,只能使用Application的Context,同時方便與Activity通信交互滿足各種需求。BaseRxActivity還可以管理RxJava生命周期。
3、異常處理
/**
- Created by Weiss on 2017/2/9.
*/
public class RxException<T extends Throwable> implements Consumer<T> {
private static final String TAG = "RxException";
private static final String SOCKETTIMEOUTEXCEPTION = "網絡連接超時,請檢查您的網絡狀態,稍后重試";
private static final String CONNECTEXCEPTION = "網絡連接異常,請檢查您的網絡狀態";
private static final String UNKNOWNHOSTEXCEPTION = "網絡異常,請檢查您的網絡狀態";
private Consumer<? super Throwable> onError;
public RxException(Consumer<? super Throwable> onError) {
this.onError=onError;
}
/**
* Consume the given value.
*
* @param t the value
* @throws Exception on error
*/
@Override
public void accept(T t) throws Exception {
if (t instanceof SocketTimeoutException) {
Log.e(TAG, "onError: SocketTimeoutException----" + SOCKETTIMEOUTEXCEPTION);
ToastUtils.show(SOCKETTIMEOUTEXCEPTION);
onError.accept(new Throwable(SOCKETTIMEOUTEXCEPTION));
} else if (t instanceof ConnectException) {
Log.e(TAG, "onError: ConnectException-----" + CONNECTEXCEPTION);
ToastUtils.show(CONNECTEXCEPTION);
onError.accept(new Throwable(CONNECTEXCEPTION));
} else if (t instanceof UnknownHostException) {
Log.e(TAG, "onError: UnknownHostException-----" + UNKNOWNHOSTEXCEPTION);
ToastUtils.show(UNKNOWNHOSTEXCEPTION);
onError.accept(new Throwable(UNKNOWNHOSTEXCEPTION));
} else {
Log.e(TAG, "onError:----" + t.getMessage());
onError.accept(t);
}
}
}</code></pre>
封裝后 (BaseRxActivity的子類使用):
addRxDestroy(Api.getInstance().movieService
.getGankData("Android",1)
.compose(RxSchedulers.io_main())
.compose(handleResult())
.subscribe(httpResult -> adapter.setItems(httpResult.data),
new RxException<>(e ->e.printStackTrace()))
);
4、多頁請求封裝
實體類:
/**
- Created by Weiss on 2017/1/20.
*/
public class Gank extends BaseListEntity {
@Override
public Flowable<HttpResult<List<Gank>>> getPage(int page) {
return GankApi.getInstance().service.getGankData(param.get("gank"), page)
.compose(RxSchedulers.io_main());
}
}</code></pre>
實體類繼承 BaseListEntity,實現getPage方法即可。
UI視圖:
public class MainActivityFragment extends BaseRxFragment {
@BindView(R.id.baseRecyclerView)
PtrRecyclerView ptrRecyclerView;
private MultiTypeAdapter adapter;
public MainActivityFragment() {
}
@Override
protected int getLayoutId() {
return R.layout.fragment_main;
}
@Override
protected void initView() {
ptrRecyclerView.setParam("gank","Android");
adapter = new MultiTypeAdapter();
adapter.register(Gank.class,new GankViewProvider());
ptrRecyclerView.setAdapter(adapter,new Gank());
}
}</code></pre>
只需要寫一個適配器和實體類,輕松實現多頁請求,PtrRecyclerView下拉刷新和上拉加載自動獲取數據。
PtrRecyclerView目前只是簡單實現下拉刷新和上拉加載,有空會完善,當然例子也會完善。
后記
還可以封裝網絡加載對話框,這個看個人喜好,同樣以上封裝同樣可以看個人喜好和項目需求自由組裝。
來自:http://www.jianshu.com/p/4005bc4a20f2