有时有多个事件,但是我们需要汇集多个事件的结果返回。比如有个系统检测,分三个部分检测,分别是电气系统检测、安全系统检测、驱动系统检测。
检测结果封装:
public class CheckOutCome {
public Boolean isSuccess = false;//检测是否成功
public String Name;//项目名称
public CheckOutCome(Boolean isSuccess, String name) {
this.isSuccess = isSuccess;
Name = name;
}
下面是我们的屏幕:
Observer ourScreen = new Observer<CheckOutCome>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Logger.log("检测开始", "");
}
@Override
public void onNext(@NonNull CheckOutCome o) {
Logger.log("ourScreen", "检测:" + o.Name+" 是否成功:"+o.isSuccess);
}
@Override
public void onError(@NonNull Throwable e) {
Logger.log("ourScreen onError", ""+e.getMessage());
}
@Override
public void onComplete() {
Logger.log("检测完成", "");
}
};
分别有三个检测模块:
Observable electricChecker = Observable.create(new ObservableOnSubscribe<CheckOutCome>() {
@Override
public void subscribe(final @NonNull ObservableEmitter<CheckOutCome> e) throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);//检测需要3秒
} catch (InterruptedException e1) {
e1.printStackTrace();
}
e.onNext(new CheckOutCome(true,"电器系统检测"));
e.onComplete();
}
}).start();
}
});
Observable safeChecker = Observable.create(new ObservableOnSubscribe<CheckOutCome>() {
@Override
public void subscribe(final @NonNull ObservableEmitter<CheckOutCome> e) throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);//检测需要1秒
} catch (InterruptedException e1) {
e1.printStackTrace();
}
e.onNext(new CheckOutCome(true,"安全系统检测"));
e.onComplete();
}
}).start();
}
});
Observable driverChecker = Observable.create(new ObservableOnSubscribe<CheckOutCome>() {
@Override
public void subscribe(final @NonNull ObservableEmitter<CheckOutCome> e) throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);//检测需要2秒
} catch (InterruptedException e1) {
e1.printStackTrace();
}
e.onNext(new CheckOutCome(true,"驱动系统检测"));
e.onComplete();
}
}).start();
}
});
1.事件合并
现在需求是,三个模块进行检测,检测完成返回结果显示在屏幕上,有一个检测出现问题,屏幕显示有问题,然后停止检测: 通过merge来合并事件,它的作用是遍历事件,如果有一个出现问题,然后异常。
Observable observable = Observable.merge(electricChecker,safeChecker,driverChecker);
observable.subscribe(ourScreen);
打印结果:
检测开始:
ourScreen:检测:安全系统检测 是否成功:true
ourScreen:检测:驱动系统检测 是否成功:true
ourScreen:检测:电器系统检测 是否成功:true
检测完成:
如果安全检测返回是这样:
e.onNext(new CheckOutCome(true,"安全系统检测"));
e.onError(new Exception("安全系统检测出问题了"));
打印结果如下:
检测开始:
ourScreen:检测:安全系统检测 是否成功:true
ourScreen onError:安全系统检测出问题了
假如我想这样,汇总所有检测结果,所有结果都没问题了才返回检测成功,否则返回有问题。
将安全检测改为如下:
e.onNext(new CheckOutCome(false,"安全系统检测"));
e.onComplete();
运行打印如下:
检测开始:
ourScreen:检测:安全系统检测 是否成功:false
ourScreen:检测:驱动系统检测 是否成功:true
ourScreen:检测:电器系统检测 是否成功:true
检测完成:
我想要的结果是,全部是ture返回检测成功,全部是false,返回检测失败。
这时可以通过zip来合并组合返回结果。
Observable observable = Observable.zip(electricChecker, safeChecker, driverChecker, new Function3<CheckOutCome, CheckOutCome, CheckOutCome, CheckOutCome>() {
@Override
public CheckOutCome apply(@NonNull CheckOutCome o, @NonNull CheckOutCome o2, @NonNull CheckOutCome o3) throws Exception {
if (o.isSuccess && o2.isSuccess && o3.isSuccess) {
return new CheckOutCome(true, "检测成功");
}
return new CheckOutCome(false, "检测失败");
}
});
observable.subscribe(ourScreen);
打印结果如下:
检测开始:
ourScreen:检测:检测失败 是否成功:false
检测完成:
这个可以应用与很多地方,比如一个页面获取数据需要去多个接口获取,如果我需要全部获取成功后才显示成功,如果有一个获取失败就显示异常,就可以这样处理。
值得注意的是,如果其中一个事件出现异常返回onError,会直接回调onError。如安全检测变为如下时:
Observable safeChecker = Observable.create(new ObservableOnSubscribe<CheckOutCome>() {
@Override
public void subscribe(final @NonNull ObservableEmitter<CheckOutCome> e) throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(6000);//检测需要6秒
} catch (InterruptedException e1) {
e1.printStackTrace();
}
//e.onNext(new CheckOutCome(false, "安全系统检测"));使用onError就不要使用这个,会出问题的
e.onError(new Exception("安全系统检测出异常"));
}
}).start();
}
});
打印结果如下:
检测开始:
ourScreen onError:
2.事件连接
假如现在想要这样:我先检测安全系统,再检测电气系统,再检测驱动系统,只要有一个出现有问题就停止检测。
其实可以通过concatmap将结果处理然后返回结果,但是真的需要实现这个需求,可以通过concat来实现,它是可以使事件迭代下去。
Observable electricChecker = Observable.create(new ObservableOnSubscribe<CheckOutCome>() {
@Override
public void subscribe(final @NonNull ObservableEmitter<CheckOutCome> e) throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);//检测需要3秒
} catch (InterruptedException e1) {
e1.printStackTrace();
}
e.onNext(new CheckOutCome(false, "电器系统检测"));
e.onComplete();
}
}).start();
}
});
Observable safeChecker = Observable.create(new ObservableOnSubscribe<CheckOutCome>() {
@Override
public void subscribe(final @NonNull ObservableEmitter<CheckOutCome> e) throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);//检测需要1秒
} catch (InterruptedException e1) {
e1.printStackTrace();
}
e.onNext(new CheckOutCome(false, "安全系统检测"));
e.onComplete();
}
}).start();
}
});
Observable driverChecker = Observable.create(new ObservableOnSubscribe<CheckOutCome>() {
@Override
public void subscribe(final @NonNull ObservableEmitter<CheckOutCome> e) throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);//检测需要2秒
} catch (InterruptedException e1) {
e1.printStackTrace();
}
e.onNext(new CheckOutCome(false, "驱动系统检测"));
e.onComplete();
}
}).start();
}
});
Observable observable = Observable.concat(safeChecker,electricChecker,driverChecker);
observable.subscribe(ourScreen);
打印如下:
检测开始:
ourScreen:检测:安全系统检测 是否成功:false
ourScreen:检测:电器系统检测 是否成功:false
ourScreen:检测:驱动系统检测 是否成功:false
检测完成:
那如何使第一个返回后进停止呢,可以通过以下代码获取第一个事件:
Observable observable = Observable.concat(safeChecker,electricChecker,driverChecker).firstElement().toObservable();
observable.subscribe(ourScreen);
打印结果:
检测开始:
ourScreen:检测:安全系统检测 是否成功:false
检测完成:
假如不是安全系统检测出问题了,那我们把这句注释:
// e.onNext(new CheckOutCome(false, "安全系统检测"));
e.onComplete();
打印结果如下:
检测开始:
ourScreen:检测:电器系统检测 是否成功:false
检测完成:
可以看到下一个检测失败的信息将会返回。
这个可以应用在一些场景中:实现本地搜索,比如可以搜关键字,按照权重关键字先后在标题、用户名、地址、状态中匹配。匹配成功就返回不进行下面的匹配,就可以通过这个链式进行匹配了。