现在的Android客户端项目中运用RxJava+Retrofit2基本上已经是主流了。
RxJava的优点就不赘述了,对于RxJava还不熟悉的可以在CSDN多找找相关的文章,都写得很好。
如果不对RxJava的Observer二次封装的话,每次新建订阅都要加线程切换,复写方法,比较繁琐。所以我们就有一个二次封装的需求。我将项目中我设计的封装分享出来,至于为什么要这么封装,我在源码里面加注释,相信大家应该能看懂。
源码点击这里
RxUtil
中,方法都一并注释了。也可参考源码地址。代码文件主要有
RxUtil
package custom.sunday.com.sharedemo.component.rx;
import android.support.annotation.StringRes;
import android.text.TextUtils;
import android.util.Log;
import java.util.List;
import custom.sunday.com.sharedemo.HomeApplication;
import custom.sunday.com.sharedemo.R;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
/**
* Created by Administrator on 2017/8/14.
*/
public class RxUtil {
/**
* 线程切换,用一个方法代替,免去手抖打错线程
* */
public static ObservableTransformer applySchedulers() {
return new ObservableTransformer() {
@Override
public Observable apply(Observable observable) {
return observable.subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread());
}
};
}
/**
* RxJava2.0中不允许发送空指针,所以需要在这里判断如果为空,则发送empty
* 后台格式固定为RootBean
* private String error; //错误码
* private String logID; //调试ID
* private String desc; //详细描述
* private T result; //我们关心的数据
* 我们只对数据感兴趣,所以使用此方法转换Observable只拿result
* */
public static ObservableTransformer, T> handleResult() {
return new ObservableTransformer, T>() {
@Override
public Observable apply(Observable> rootBeanObservable) {
return rootBeanObservable.flatMap(new Function, Observable>() {
@Override
public Observable apply(RootBean rootBean) {
if (rootBean.getError().equals(HttpCode.SUCCESS)) {
if (rootBean.getResult() == null) {
return Observable.empty();
} else {
return Observable.just(rootBean.getResult());
}
} else {
return Observable.error(new NormalException(
rootBean.getError(),
rootBean.getDesc(),
rootBean.getLogID()));
}
}
});
}
};
}
/**
* PageData
* private int pageTotal;
* private int pageNo;
* private List pageData;
* 同样的,在APP中分页数据很常见,所以封装了PageData,直接将数据变换为List
* */
public static ObservableTransformer>, List> handlePageResult() {
return new ObservableTransformer>, List>() {
@Override
public ObservableSource> apply(Observable>> observable) {
return observable.flatMap(new Function>, ObservableSource>>() {
@Override
public ObservableSource> apply(RootBean> rootBean) throws Exception {
if (rootBean.getError().equals(HttpCode.SUCCESS)) {
if (rootBean.getResult() == null) {
return Observable.empty();
} else {
return Observable.just(rootBean.getResult().getPageData());
}
} else {
return Observable.error(new NormalException(
rootBean.getError(),
rootBean.getDesc(),
rootBean.getLogID()));
}
}
});
}
};
}
/**
* 这里有一个重要的接口RxLife,此RxLife由baseActivity或者baseFragment实现,
* 用于记录Disposable来实现界面和请求的生命周期同步,当在网络请求中时,离开界面,此时自动取消订阅
* 为什么要实现Disposable接口?是因为取消订阅后我们不能收到通知,所以实现Disposable后,将自身传入,
* 取消订阅时会回调dispose,用于界面更新
* **/
public abstract static class SimpleObserver<T> implements Observer<T>, Disposable {
private String tag;
private RxLife mRxLife;
private boolean haveLoading = true;
private Disposable disposable;
private int resNetDisable = R.string.net_disable_tip;
private int resNetNotWork = R.string.net_not_work_tip;
public SimpleObserver(RxLife rxLife) {
mRxLife = rxLife;
}
/**
* @param tag
* 调试异常结果,传入TAG,可以过滤多余信息
* */
public SimpleObserver(RxLife rxLife, String tag) {
mRxLife = rxLife;
this.tag = tag;
}
/**
* @param haveLoading
*
* **/
public SimpleObserver(RxLife rxLife, boolean haveLoading) {
mRxLife = rxLife;
this.haveLoading = haveLoading;
}
/**
* 获取网络中断提示语,如果界面需要单独的提示语,则覆写此方法
*/
protected int getResNetDisable() {
return resNetDisable;
}
/**
* 获取网络异常提示语,如果界面需要单独的提示语,则覆写此方法
*/
protected int getResNetNotWork() {
return resNetNotWork;
}
/**
* 隐藏网络异常提示,如果不需要网络异常提示,则覆写此方法改为true
* @return
*/
public boolean isHideErrorTip() {
return false;
}
@Override
public void onSubscribe(Disposable disposable) {
this.disposable = disposable;
if (mRxLife != null) {
mRxLife.addDisposable(this);
if (haveLoading) {
mRxLife.showLoading();
}
}
}
@Override
public void onComplete() {
if (mRxLife != null) {
mRxLife.removeDisposable(this);
if (haveLoading) {
mRxLife.hideLoading();
}
} else {
disposable.dispose();
}
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
if (mRxLife != null) {
mRxLife.removeDisposable(this);
if (haveLoading) {
mRxLife.hideLoading();
}
} else {
disposable.dispose();
}
//look HttpCode.java
String errorMsg = e.getMessage();
if (e instanceof NormalException) {
if (errorMsg.equals(HttpCode.RELOGIN)) {
//HomeApplication.getInstance().logout();
} else if (errorMsg.equals(HttpCode.SERVICE_ERROR)) {
if (mRxLife != null && !isHideErrorTip()) {
mRxLife.showErrorTips(resNetNotWork);
}
}
} else {
if (mRxLife != null && !isHideErrorTip()) {
// if (!NetworkUtil.getInstance(HomeApplication.getInstance().getApplicationContext()).isNetworkConnected()) {
// mRxLife.showErrorTips(getResNetDisable()); //网络断开提示
// } else {
// mRxLife.showErrorTips(getResNetNotWork()); //网络无法访问提示
// }
}
}
onErrorMsg(errorMsg);
}
protected void onErrorMsg(String msg) {
if (tag != null) {
Log.e("RxUtil", "tag = " + tag + " onErrorMsg | = " + msg);
} else {
Log.e("RxUtil", "onErrorMsg | = " + msg);
}
}
@Override
public void dispose() {
disposable.dispose();
}
@Override
public boolean isDisposed() {
return disposable.isDisposed();
}
@Override
public void onNext(T t) {
onResult(t);
}
abstract public void onResult(T t);
}
public static class NormalException extends Exception {
private String desc;
private String logId;
public NormalException(String msg) {
super(msg);
}
public NormalException(String msg, String desc, String logId) {
this(msg);
this.desc = desc;
this.logId = logId;
}
public String getLogId() {
return logId;
}
}
}
RxLife
public interface RxLife {
void showLoading();
void hideLoading();
void showNetworkErrorTips();
void showErrorTips(int resId);
void addDisposable(Disposable disposable);
void removeDisposable(Disposable disposable);
void disposableAll();
}
RootBean
public class RootBean<T> {
private String error;
private String logID;
private String desc;
private T result;
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public String getLogID() {
return logID;
}
public void setLogID(String logID) {
this.logID = logID;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public T getResult() {
return result;
}
public void setResult(T result) {
this.result = result;
}
}
PageData
public class PageData<T> {
private int pageTotal;
private int pageNo;
private List pageData;
public void setPageTotal(int pageTotal) {
this.pageTotal = pageTotal;
}
public int getPageTotal() {
return pageTotal;
}
public void setPageNo(int pageNo) {
this.pageNo = pageNo;
}
public int getPageNo() {
return pageNo;
}
public void setPageData(List pageData) {
this.pageData = pageData;
}
public List getPageData() {
return pageData;
}
}