RxJava3 Single 简介
本文的代码是在IntellJ环境中测试的,可以直接copy过去运行看看
IntellJ新建Gradle工程,引入依赖
implementation "io.reactivex.rxjava3:rxjava:3.0.0"
在RxJava中,Single可以描述只发送一次事件值的事件,如一次网络请求,它有2个可订阅接口,onSuccess和onError,在任何一个接口触发后会自动解除订阅关系。
//创建Single
Single<String> single = Single.create(emitter -> {
emitter.onSuccess("ok");
});
//订阅single
single.subscribe(System.out::println);
复制代码
多个Single串行执行
首先创建多个Single
public Single<String> task1() {
return Single.create((SingleOnSubscribe<String>) em -> {
em.onSuccess("task-1");
}).doOnSuccess(s -> {
System.out.println("发射 ->" + s);
});
}
public Single<String> task2() {
return Single.create((SingleOnSubscribe<String>) em -> {
em.onSuccess("task-2");
}).doOnSuccess(s -> {
System.out.println("发射 ->" + s);
});
}
复制代码
声明多个Single任务
Single<String> single1 = task1();
Single<String> single2 = task2();
复制代码
工作线程,通常直接使用Schedulers.io()
,这里用一个线程池,方便在一个线程中打印日志
Executor executor = Executors.newSingleThreadExecutor();
复制代码
场景一:串行执行并接收每个结果
Single.concat(single1, single2)
.subscribeOn(Schedulers.from(executors))
.subscribe(s -> {
System.out.println("接收到->" + s);
});
复制代码
执行结果:
发射 ->task-1
接收到->task-1
发射 ->task-2
接收到->task-2
复制代码
场景二:根据前一个single的结果,判断是否执行后一个
如先从数据库缓存中读取数据,如果没有再从网络进行请求
Single.concat(single1, single2)
.subscribeOn(Schedulers.from(executors))
.takeUntil(s -> {
return !"".equals(s);
})
.filter(s -> {
return !"".equals(s);
})
.subscribe(s -> {
System.out.println("接收到->" + s);
});
复制代码
执行结果:
发射 ->task-1
接收到->task-1
复制代码
这里使用takeUntil
和filter
操作符实现条件判断和过滤不需要的请求结果。
takeUntil
在条件返回true时,不再执行下一个Single,并直接返回结果;如果takeUntil
条件返回false,其发射的值在filter
操作符中被过滤掉,并继续执行下一个Single。
提供默认返回值和异常处理
如果多个single的执行结果都被过滤,则订阅者将收不到任何值,这时可以提供一个默认返回值;
使用single()
操作符提供结果为空时的默认返回值
使用onErrorReturn()
操作符处理异常
Single.concat(single1, single2)
.subscribeOn(Schedulers.from(executors))
.takeUntil(s -> {
return false;//此处测试全都执行
})
.filter(s -> {
return true;//此处测试全都不满足过滤条件的情况
})
.single("default-value")
.onErrorReturn(Throwable::getLocalizedMessage)
.subscribe(s -> {
System.out.println("接收到->" + s);
});
复制代码
执行结果
发射 ->task-1
发射 ->task-2
接收到->default
复制代码
阻塞的方式实现串行 (不建议使用)
使用blockingGet
阻塞工作线程,该方式会使线程阻塞而非挂起,在线程完成前系统其他资源无法使用该线程。
这里很像Kotlin
中的协程,但是协程是非阻塞的。
String str1 = single1.subscribeOn(Schedulers.from(executors)).blockingGet();
if (!"success".equals(str1)) {
single2.subscribeOn(Schedulers.from(executors))
.subscribe(System.out::println);
}
复制代码
执行结果:
发射 ->task-1
发射 ->task-2
task-2
复制代码