今天用代理模式完美解决公司项目的bug.
BUG代码
用RxJava封装的网络请求统一处理方案
public abstract class RxSubUtils extends Subscriber {
private CompositeSubscription mCompositeSubscription;
private Context mContext;
private String msg;
public RxSubUtils(){}
public RxSubUtils(CompositeSubscription mCompositeSubscription) {
this.mCompositeSubscription = mCompositeSubscription;
}
/**
* @param context context
* @param msg dialog message
*/
public RxSubUtils(CompositeSubscription mCompositeSubscription, Context context, String msg) {
this.mCompositeSubscription = mCompositeSubscription;
this.mContext = context;
this.msg = msg;
}
/**
* @param context context
*/
public RxSubUtils(CompositeSubscription mCompositeSubscription, Context context) {
this(mCompositeSubscription, context, "请稍后...");
}
/**
* 这个一定要有 Presenter的逻辑在这里处理
* @param t
*/
@Override
public void onNext(T t) {
_onNext(t);
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
LoadingDialogManager.getLoadingDialog().hideDialog();
if (!NetWorkUtils.isNetworkAvailable()) {
ToastUtil.show(R.string.net_error);
} else if (e instanceof RxUtils.ServerException) {//
String s = ((RxUtils.ServerException)e).getMsg();//
//token 过期了
//if(TextUtils.equals(s, RxUtils.TOKEN_OVER_TIME) && mContext != null){
// Utils.startLoginActivity(mContext);
// }
// ToastUtil.show(s);
} else {
ToastUtil.show(R.string.error);
}
_onError();
}
@Override
public void onCompleted() {
if (mCompositeSubscription != null)
mCompositeSubscription.remove(this);
LoadingDialogManager.getLoadingDialog().hideDialog();
}
@Override
public void onStart() {
super.onStart();
if (mContext != null) {
LoadingDialogManager.getLoadingDialog().showDialog(mContext);
}
}
protected abstract void _onNext(T t);
/**
* 错误处理,需要的话重写这个方法
*/
protected void _onError(){
}
}
1.统一处理网络请求到的数据
2.可以选择是否添加LoadingDialog
3.可以统一处理特殊情况,如用户信息过期等
使用方法:
public void getDataList(){
mCompositeSubscription.add(model.getDataList()
.subscribe(new RxSubUtils>(mCompositeSubscription) {
@Override
protected void _onNext(List videoBeen) {
getView().getVideoList(videoBeen);
}
@Override
protected void _onError() {
getView().onFail();
}
}));
}
以上封装只是部分代码,主要不是说明这个问题,APP跑起来,切换各种网络,2G,3G,wifi但访问不到后台数据,wifi能正常访问等操作,就会出现下面bug。
Stack trace is opaque for IllegalStateException: Exception thrown on Scheduler.Worker thread. Add onError handling.
看到最后说到解决方法两种:
- 一种是上面的RxSubUtils改为继承SafeSubscriber
- 一种是在使用的时候加上Throwable的处理
那么问题来了,第二种方法中上面的使用方法有成百上千个,真是不能手工一个一个改,会死人的,所以就只能用第一种方法,但是第一种方法中继承SafeSubscriber,构造函数就要改变,使用的时候还是每一个地方都要改,还是会死人
-----------------------------------------分割线-----------------------------------------
解决方案:
建立RxSafeSubUtils类继承SafeSubscriber,设置为被代理类,原来的RxSubUtils设置为代理类,改为如下
public class RxSafeSubUtils extends SafeSubscriber {
private CompositeSubscription mCompositeSubscription;
private Context mContext;
private IOSDialog dialog;
private Subscription subscription;
public RxSafeSubUtils(Subscriber super T> actual) {
super(actual);
subscription = actual;
}
public RxSafeSubUtils(Subscriber super T> actual, CompositeSubscription compositeSubscription) {
super(actual);
this.mCompositeSubscription = compositeSubscription;
subscription = actual;
}
public RxSafeSubUtils(Subscriber super T> actual, CompositeSubscription compositeSubscription, Context context) {
this(actual, compositeSubscription);
this.mContext = context;
subscription = actual;
}
/**
* 这个一定要有 Presenter的逻辑在这里处理
* @param t
*/
@Override
public void onNext(T t) {
((RxSubUtils)subscription).onNext(t);
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
if (!NetWorkUtils.isNetworkAvailable()) {
ToastUtil.show(R.string.net_error);
} else if (e instanceof RxUtils.ServerException) {
String s = ((RxUtils.ServerException)e).getMsg();
//token 过期了
if(TextUtils.equals(s, RxUtils.TOKEN_OVER_TIME) && mContext != null){
Utils.startLoginActivity(mContext);
}
ToastUtil.show(s);
} else {
ToastUtil.show(R.string.error);
}
if (dialog!= null){
dialog.dismiss();
dialog = null;
}
((RxSubUtils)subscription)._onError();
}
@Override
public void onCompleted() {
if (mCompositeSubscription != null)
mCompositeSubscription.remove(this);
if (dialog != null) {
dialog.dismiss();
dialog = null;
}
}
@Override
public void onStart() {
super.onStart();
if (mContext != null && dialog == null) {
dialog = new IOSDialog(mContext).builder()
.setLoadingView(R.color.colorPrimary);
dialog.show();
}
}
}
public abstract class RxSubUtils extends Subscriber {
private RxSafeSubUtils rxSafeSubUtils;
public RxSubUtils() {
rxSafeSubUtils = new RxSafeSubUtils(this);
}
public RxSubUtils(CompositeSubscription mCompositeSubscription) {
rxSafeSubUtils = new RxSafeSubUtils(this, mCompositeSubscription);
}
/**
* @param context context
*/
public RxSubUtils(CompositeSubscription mCompositeSubscription, Context context) {
rxSafeSubUtils = new RxSafeSubUtils(this, mCompositeSubscription, context);
}
/**
* 这个一定要有 Presenter的逻辑在这里处理
* @param t
*/
public void onNext(T t) {
_onNext(t);
}
@Override
public void onError(Throwable e) {
_onError();
}
@Override
public void onCompleted() {
rxSafeSubUtils.onCompleted();
}
@Override
public void onStart() {
rxSafeSubUtils.onStart();
}
protected abstract void _onNext(T t);
/**
* 错误处理,需要的话重写这个方法
*/
protected void _onError(){
}
}
这样用的时候, 代码什么都不改,完美解决!
PS:最好的方法还是在开始的时候就想到封装RxSafeSubUtils,不用任何代理!