RxJava 3 在项目中用了一两年了,作为响应式框架,提升系统响应速度还是挺不错的;
RxJava 3 是一个基于响应式编程思想的 Java 库,用于处理异步数据流和事件流。它是 RxJava 2 的升级版本,带来了许多新特性和改进。(RxJava官网:ReactiveX)
目录
1.项目中引入RxJava3依赖,java项目使用Maven
5.用Single和Observable的示例的对比来解释说明single只能发出0个或1个元素
一、主要特性
1. 性能优化:RxJava 3 在订阅和取消订阅方面进行了优化,提升了整体性能。
2. 类型系统改进:增加了对原始类型、协变类型和逆变类型的支持,使得操作符和流的创建更加灵活。
3. 错误处理增强:新增了如 onErrorReturn 和 onErrorResume 等操作符,提供了更灵活的错误处理机制。
4. Kotlin 协程支持:RxJava 3 支持 Kotlin 协程,方便在 Kotlin 项目中使用。
5. 响应式流支持:引入了 Java 9 的 Flow 接口, Flowable 类实现了 Flow.Publisher 接口,支持背压。
6. 操作符扩展:新增了 zipWith 和 concatWith 等操作符,用于组合和连接数据源。
主要核心组件
1. Observable 和 Observer: Observable 是数据源, Observer 是订阅者,用于接收数据。
2. Flowable 和 Subscriber: Flowable 是支持背压的 Observable ,用于处理生产者和消费者速度不匹配的情况。
3. Scheduler:用于控制代码运行的线程,支持异步和并发操作。
二、详细介绍:
以下是 RxJava 3 中的主要组件和工具类的详细介绍:
1.核心组件
1.1 Observable
• 描述:表示一个可以发出零个或多个数据项的数据源。
• 特点:
• 不支持背压。
• 适合用于不需要严格控制数据流速度的场景。
• 使用示例:
Observable.just("Hello", "World")
.subscribe(System.out::println);
1.2 Flowable
• 描述:类似于`Observable`,但支持背压机制。
• 特点:
• 支持背压,适合处理数据生产者和消费者速度不匹配的情况。
• 遵循 Reactive-Streams 规范。
• 使用示例:
Flowable.range(1, 10)
.observeOn(Schedulers.computation())
.map(i -> i * i)
.subscribe(System.out::println);
1.3 Single
• 描述:只能发出一个数据项或一个错误。
• 特点:
• 适用于只需要一个结果的场景。
• 使用示例:
Single.just(42)
.subscribe(System.out::println, Throwable::printStackTrace);
1.4 Maybe
• 描述:可以发出零个或一个数据项。
• 特点:
• 适合可能没有结果的场景。
• 使用示例:
Maybe.just("Hello")
.subscribe(System.out::println, Throwable::printStackTrace, () -> System.out.println("Completed"));
1.5 Completable
• 描述:不发出任何数据,只处理`onComplete`和`onError`事件。
• 特点:
• 适用于只需要完成或失败的场景。
• 使用示例:
Completable.complete()
.subscribe(() -> System.out.println("Completed"), Throwable::printStackTrace);
2.订阅者相关
2.1 Observer
• 描述:用于订阅`Observable`或`Flowable`,并接收数据。
• 特点:
• 需要实现`onNext`、`onError`和`onComplete`方法。
• 使用示例:
Observer<String> observer = new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {}
@Override
public void onNext(String s) {
System.out.println(s);
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
System.out.println("Completed");
}
};
Observable.just("Hello", "World").subscribe(observer);
2.2 Subscriber
• 描述:`Subscriber`是`Observer`的一个扩展,用于订阅`Flowable`。
• 特点:
• 支持背压。
• 使用示例:
Subscriber<Integer> subscriber = new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
s.request(1); // 请求数据
}
@Override
public void onNext(Integer integer) {
System.out.println(integer);
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
@Override
public void onComplete() {
System.out.println("Completed");
}
};
Flowable.range(1, 10).subscribe(subscriber);
3.调度器(Schedulers)
• 描述:用于控制代码的执行线程。
• 常见调度器:
• `Schedulers.computation()`:用于计算密集型任务。
• `Schedulers.io()`:用于 I/O 操作。
• `Schedulers.newThread()`:为每个任务创建新线程。
• `Schedulers.trampoline()`:在当前线程中顺序执行任务。
• `AndroidSchedulers.mainThread()`(需要`RxAndroid`):切换到 Android 主线程。
• 使用示例:
Flowable.range(1, 10)
.subscribeOn(Schedulers.io()) // 指定数据源执行线程
.observeOn(Schedulers.computation()) // 指定观察者执行线程
.subscribe(System.out::println);
4.操作符(Operators)
• 描述:用于对数据流进行转换、过滤、合并等操作。
• 常见操作符:
• 变换操作符:
• `map`:对数据进行转换。
• `flatMap`:将数据流中的每个数据项展开为一个新的数据流。
• `concatMap`:与`flatMap`类似,但保证数据顺序。
• 过滤操作符:
• `filter`:过滤数据流中的数据。
• `take`:只取前 N 个数据。
• `distinct`:去重。
• 组合操作符:
• `merge`:合并多个数据流。
• `zip`:将多个数据流的元素组合成一个。
• 错误处理操作符:
• `onErrorReturn`:返回一个默认值。
• `onErrorResumeNext`:用另一个数据流替换错误。
• 背压操作符:
• `onBackpressureDrop`:丢弃多余的数据。
• `onBackpressureBuffer`:缓冲多余的数据。
5.工具类
5.1 Disposable
• 描述:表示一个可取消的订阅。
• 使用示例:
Disposable disposable = Observable.just("Hello")
.subscribe(System.out::println);
disposable.dispose(); // 取消订阅
5.2 CompositeDisposable
• 描述:用于管理多个`Disposable`对象。
• 使用示例:
CompositeDisposable compositeDisposable = new CompositeDisposable();
compositeDisposable.add(Observable.just("Hello").subscribe(System.out::println));
compositeDisposable.add(Observable.just("World").subscribe(System.out::println));
compositeDisposable.dispose(); // 取消所有订阅
5.3 Emitter
• 描述:用于创建自定义的`Observable`或`Flowable`。
• 使用示例:
Observable.create(emitter -> {
emitter.onNext("Hello");
emitter.onNext("World");
emitter.onComplete();
}).subscribe(System.out::println);
6.其他工具类
6.1 Subject
• 描述:既是`Observable`又是`Observer`,用于桥接不同的数据流。
• 常见类型:
• `PublishSubject`:只发送订阅后发出的数据。
• `BehaviorSubject`:发送最近一次数据及后续数据。
• `ReplaySubject`:发送所有历史数据。
• `AsyncSubject`:只发送最后一个数据。
• 使用示例:
PublishSubject<String> subject = PublishSubject.create();
subject.subscribe(System.out::println);
subject.onNext("Hello");
subject.onNext("World");
subject.onComplete();
6.2 Processors
• 描述:类似于`Subject`,但支持背压。
• 常见类型:
• `FlowableProcessor`:支持背压的`Subject`。
• `UnicastProcessor`:一对一的处理器。
• `BroadcastProcessor`:一对多的处理器。
7.包结构
根据,RxJava 3 的组件位于`io.reactivex.rxjava3`包下,具体结构如下:
• Core:`io.reactivex.rxjava3.core`
• Annotations:`io.reactivex.rxjava3.annotations`
• Disposables:`io.reactivex.rxjava3.disposables`
• Exceptions:`io.reactivex.rxjava3.exceptions`
• Functions:`io.reactivex.rxjava3.functions`
• Observers:`io.reactivex.rxjava3.observers`
• Subjects:`io.reactivex.rxjava3.subjects`
• Processors:`io.reactivex.rxjava3.processors`
三.完整集成及使用示例
1.项目中引入RxJava3依赖,java项目使用Maven
<!-- RxJava 3 -->
<dependency>
<groupId>io.reactivex.rxjava3</groupId>
<artifactId>rxjava</artifactId>
<version>3.1.3</version>
</dependency>
<!-- MyBatis Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.4</version>
</dependency>
<!-- 数据库驱动,以MySQL为例 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
如果项目中有使用到Redisson,那么无需再引入Rxjava3的依赖,因为Redisson已经依赖了Rxjava3。
android项目是用gradle;在项目中引入 RxJava 3 的依赖。如果是 Android 项目,还需要添加 RxAndroid。
implementation 'io.reactivex.rxjava3:rxjava:3.1.1'
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
2.使用示例
配置MyBatis Plus创建实体类 User 和Mapper接口 UserMapper :
// 实体类
public class User {
private Long id;
private String name;
// getter和setter省略
}
// Mapper接口
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
创建Service
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public Flowable<List<User>> getAllUsers() {
return Flowable.defer(() -> {
List<User> users = userMapper.selectList(null);
return Flowable.just(users);
});
}
}
使用RxJava 3处理数据在你的业务逻辑中,你可以这样使用Service:
public class RxJavaService {
@Autowired
private UserService userService;
public void processUsers() {
userService.getAllUsers()
.subscribeOn(Schedulers.io()) // 指定在IO线程上执行数据库查询
.observeOn(Schedulers.computation()) // 指定在计算线程上处理数据
.subscribe(users -> {
// 处理用户数据
users.forEach(user -> {
// 对每个用户进行处理
System.out.println(user.getName());
});
});
}
}
除了使用Flowable处理外,还有其他方式的api来做这种异步处理,所以可以换作其他写法
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public Observable<List<User>> getAllUsers() {
return Observable.create(emitter -> {
List<User> users = userMapper.selectList(null);
emitter.onNext(users);
emitter.onComplete();
}).subscribeOn(Schedulers.io()); // 指定在IO线程上执行数据库查询
}
}
在你的业务逻辑中,可以这样使用Service:
public class RxJavaService {
@Autowired
private UserService userService;
public void processUsers() {
userService.getAllUsers()
.observeOn(Schedulers.computation()) // 指定在计算线程上处理数据
.subscribe(users -> {
// 处理用户数据
users.forEach(user -> {
// 对每个用户进行处理
System.out.println(user.getName());
});
});
}
}
或者还可能使用到 Single 和 flatMap
Single 是RxJava中用于表示单个结果的异步处理API。你可以使用 Single.create() 来创建一个 Single ,然后通过 flatMap 来处理多个异步请求的顺序执行。
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.schedulers.Schedulers;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public Single<List<User>> getAllUsers() {
return Single.create(emitter -> {
List<User> users = userMapper.selectList(null);
emitter.onSuccess(users);
}).subscribeOn(Schedulers.io()); // 指定在IO线程上执行数据库查询
}
}
在你的业务逻辑中,可以这样使用Service:
public class RxJavaService {
@Autowired
private UserService userService;
public void processUsers() {
userService.getAllUsers()
.observeOn(Schedulers.computation()) // 指定在计算线程上处理数据
.subscribe(users -> {
// 处理用户数据
users.forEach(user -> {
// 对每个用户进行处理
System.out.println(user.getName());
});
});
}
}
在RxJava中, Observable 可以指定背压(backpressure)策略。背压是一种控制数据流速率的机制,用于处理生产者(数据生成方)和消费者(数据处理方)之间的速率不匹配问题。在RxJava中,背压策略可以通过 onBackpressure* 系列操作符来指定。
以下是RxJava 3中可用的背压策略及其对应的操作符:
1. onBackpressureBuffer() :使用一个缓冲区来存储超出消费者处理能力的项目,直到消费者能够处理它们。如果缓冲区满了,新的项目会导致错误。
2. onBackpressureDrop() :如果消费者处理不过来,会丢弃新的项目。
3. onBackpressureLatest() :如果消费者处理不过来,会丢弃旧的项目,只保留最新的项目。
4. onBackpressureError() :如果消费者处理不过来,会发出一个错误信号。
例如,如果你想要使用 onBackpressureBuffer() 策略,可以这样写:
Observable.just(1, 2, 3, 4, 5)
.onBackpressureBuffer()
.subscribe(item -> {
// 这里模拟消费者处理数据的速度较慢
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Processed: " + item);
});
在这个例子中, onBackpressureBuffer() 操作符会创建一个默认大小的缓冲区来存储项目,直到消费者能够处理它们。如果消费者处理速度慢,生产者会先将项目放入缓冲区,而不会阻塞生产者。请注意,背压策略的选择取决于你的具体需求和场景。
在某些情况下,可能需要自定义缓冲区的大小,这时可以使用 onBackpressureBuffer(long capacity) 来指定缓冲区的大小。如果缓冲区大小为 Long.MAX_VALUE ,则表示无界缓冲区,这可能会导致内存溢出。
四.总结及详细示例
1.Observable与Single的区别
`Observable`和`Single`是RxJava中两种不同的响应式编程类型,它们的主要区别在于它们可以发出的元素数量和用例。以下是它们的主要区别:
• 发出的元素数量:
• `Observable`:可以发出0个或多个元素,也可以发出一个错误通知,或者是一个完成通知。
• `Single`:只能发出0个或1个元素,或者是一个错误通知。如果发出超过一个元素,它会立即发出一个错误。
• 用例:
• `Observable`:适用于需要处理一个元素序列的场景,例如监听按钮点击事件流、处理多个网络请求的响应等。
• `Single`:适用于需要处理单个结果的场景,例如获取用户信息、执行数据库查询等,这些操作最终只返回一个结果或者失败。
• 错误处理:
• `Observable`:如果发出错误,可以通过`onError`回调来处理,并且可以继续发出其他元素。
• `Single`:如果发出错误,它会终止序列,不再发出任何元素。
• 生命周期:
• `Observable`:可以有更长的生命周期,可以持续发出元素,直到被显式地取消订阅。
• `Single`:通常有更短的生命周期,一旦发出元素或者错误,序列就完成了。
• 操作符:
• `Observable`:提供了一些专门用于处理多个元素的操作符,如`buffer`、`window`、`merge`等。
• `Single`:提供了一些用于确保只发出一个元素的操作符,如`first`、`last`、`elementAt`等。
• 性能和资源管理:
• `Observable`:由于可以发出多个元素,需要更多的资源来处理元素序列,例如需要维护一个订阅者列表。
• `Single`:由于只发出一个元素,通常资源消耗更少,也更容易管理。
• 转换:
• 你可以将`Observable`转换为`Single`,例如通过使用`first`、`last`、`single`等操作符。
• 你也可以将`Single`转换为`Observable`,例如通过使用`toObservable`方法。
选择`Observable`还是`Single`取决于你的具体需求。如果你的流中只有一个结果,使用`Single`可以更清晰地表达你的意图,并且有助于避免背压问题。如果你需要处理多个结果,那么`Observable`是更合适的选择。
2.Completable使用示例
`Completable`是RxJava中用于表示没有返回值的异步操作,它只关心操作的完成或者错误。以下是`Completable`的一个使用示例:
示例场景
假设我们有一个异步任务,比如保存用户设置到数据库,这个操作不需要返回任何数据,我们只关心操作是否成功或者失败。
1.创建一个`Completable`源
首先,我们创建一个`Completable`源,它将执行异步操作:
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.schedulers.Schedulers;
public class CompletableExample {
public static void main(String[] args) {
// 创建Completable源
Completable completable = Completable.create(emitter -> {
// 模拟异步操作,比如保存设置到数据库
new Thread(() -> {
try {
// 模拟耗时操作
Thread.sleep(2000);
// 操作成功
emitter.onComplete();
} catch (Exception e) {
// 操作失败
emitter.onError(e);
}
}).start();
});
// 订阅Completable
completable
.subscribeOn(Schedulers.io()) // 指定在IO线程上执行异步操作
.observeOn(Schedulers.single()) // 指定在单线程上观察结果
.subscribe(() -> {
// 操作完成
System.out.println("Settings saved successfully!");
}, Throwable::printStackTrace); // 处理错误
}
}
2.订阅`Completable`
在上面的代码中,我们通过`subscribe`方法订阅了`Completable`。`Completable`的`subscribe`方法接受两个参数:一个用于处理完成事件的`Action`,另一个用于处理错误事件的`Consumer<Throwable>`。
3.指定调度器
我们使用`subscribeOn`来指定`Completable`源应该在哪个调度器上执行,这里我们选择了`Schedulers.io()`,意味着我们的异步操作将在IO线程上执行。然后,我们使用`observeOn`来指定观察者应该在哪个调度器上接收事件,这里我们选择了`Schedulers.single()`,这是一个用于串行执行任务的调度器。
4.处理完成和错误
在`subscribe`方法中,我们提供了一个lambda表达式来处理完成事件,以及一个`Throwable::printStackTrace`方法引用来处理错误事件。
这个示例展示了如何使用`Completable`来表示和处理没有返回值的异步操作。`Completable`非常适合用于那些只关心操作是否成功完成或者失败的场景。
3.Maybe的使用示例
`Maybe`类型在 RxJava 中用于表示可能发出单个元素或者不发出元素(空)的异步序列。以下是`Maybe`的一个使用示例:
示例场景
假设我们有一个异步任务,比如根据用户ID查询用户信息,如果用户存在,则返回用户信息;如果用户不存在,则不返回任何数据。
1.创建一个`Maybe`源
首先,我们创建一个`Maybe`源,它将执行异步操作:
import io.reactivex.rxjava3.core.Maybe;
import io.reactivex.rxjava3.schedulers.Schedulers;
public class MaybeExample {
public static void main(String[] args) {
// 模拟根据用户ID查询用户信息的异步操作
Maybe<User> maybeUser = Maybe.create(emitter -> {
// 模拟数据库查询
new Thread(() -> {
try {
// 模拟耗时操作
Thread.sleep(1000);
// 假设我们找到了用户
User user = new User(1, "John Doe");
emitter.onSuccess(user); // 发出一个用户
} catch (InterruptedException e) {
// 如果查询被中断,发出错误
emitter.onError(e);
}
}).start();
});
// 订阅Maybe
maybeUser
.subscribeOn(Schedulers.io()) // 指定在IO线程上执行异步操作
.observeOn(Schedulers.computation()) // 指定在计算线程上观察结果
.subscribe(
user -> System.out.println("User found: " + user.getName()), // 处理用户信息
Throwable::printStackTrace, // 处理错误
() -> System.out.println("No user found.") // 处理空情况,即没有用户
);
}
static class User {
private int id;
private String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
}
}
2.订阅`Maybe`
在上面的代码中,我们通过`subscribe`方法订阅了`Maybe`。`Maybe`的`subscribe`方法接受三个参数:一个用于处理成功事件的`Consumer`,一个用于处理错误事件的`Consumer<Throwable>`,以及一个用于处理空情况的`Action`。
3.指定调度器
我们使用`subscribeOn`来指定`Maybe`源应该在哪个调度器上执行,这里我们选择了`Schedulers.io()`,意味着我们的异步操作将在 IO 线程上执行。然后,我们使用`observeOn`来指定观察者应该在哪个调度器上接收事件,这里我们选择了`Schedulers.computation()`,这是一个用于并行执行计算任务的调度器。
4.处理成功、错误和空情况
在`subscribe`方法中,我们提供了一个 lambda 表达式来处理成功事件(用户信息),一个`Throwable::printStackTrace`方法引用来处理错误事件,以及一个空的 lambda 表达式来处理空情况(没有找到用户)。
这个示例展示了如何使用`Maybe`来表示和处理可能发出单个元素或者不发出元素的异步操作。`Maybe`非常适合用于那些可能成功也可能失败,或者可能返回一个结果也可能不返回结果的场景。
4.如何理解Single只能发出0个或者一个元素
`Single`是 RxJava 中的一种特殊类型的 Observable,它只能发出一个元素或者一个错误通知,而不能发出多个元素。这种设计有几个关键点需要理解:
• 单一结果:`Single`用于表示那些最终会产生单一结果的操作,比如从数据库查询一条记录、执行一个网络请求获取单个响应等。这些操作要么成功并返回一个结果,要么失败并返回一个错误。
• 不可重复:由于`Single`只能发出一个元素,它保证了发出的元素是唯一的,这有助于避免在处理结果时的歧义。如果一个操作可能产生多个结果,那么使用`Single`就不合适,而应该使用`Observable`或`Flowable`。
• 背压支持:`Single`支持背压(backpressure),这意味着它可以与遵守背压的消费者协同工作,确保不会因为生产者发出元素的速度过快而导致消费者处理不过来。
• 错误处理:如果操作失败,`Single`会发出一个错误通知,而不是多个错误。这使得错误处理更加简单和一致。
• 完成通知:在成功发出一个元素之后,`Single`会发出一个完成通知,表明不会再有更多的元素发出。如果`Single`没有发出任何元素,它也只会发出一个完成通知,表示操作没有结果。
• 不可变性:一旦`Single`发出了一个元素或者错误,它就被认为是完成的,不能再发出更多的元素。这种不可变性使得`Single`在某些场景下比`Observable`更易于使用,因为它减少了处理多个元素的复杂性。
• 转换和组合:`Single`提供了丰富的操作符来转换和组合`Single`源,比如`flatMap`、`zip`、`merge`等,这些操作符可以帮助你构建复杂的异步逻辑,同时保持代码的清晰和简洁。
总的来说,`Single`的设计哲学是简化异步操作的处理,特别是在那些只关心单一结果的场景中。通过限制只能发出一个元素,`Single`提供了一种更清晰、更易于管理的方式来处理异步数据流。
5.用Single和Observable的示例的对比来解释说明single只能发出0个或1个元素
为了更直观地理解`Single`和`Observable`之间的区别,特别是`Single`只能发出0个或1个元素的特性,我们可以创建两个示例:一个使用`Single`来获取单个用户信息,另一个使用`Observable`来获取多个用户信息。
使用`Single`获取单个用户信息
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.schedulers.Schedulers;
public class SingleExample {
public static void main(String[] args) {
// 假设这是一个数据库查询操作,它返回一个用户信息或者在失败时返回一个错误
Single<User> singleUser = Single.fromCallable(() -> {
// 模拟数据库查询
// 假设我们找到了用户
return new User(1, "John Doe");
});
// 订阅Single
singleUser
.subscribeOn(Schedulers.io()) // 指定在IO线程上执行异步操作
.observeOn(Schedulers.computation()) // 指定在计算线程上观察结果
.subscribe(
user -> System.out.println("User found: " + user.getName()), // 处理用户信息
error -> error.printStackTrace() // 处理错误
);
}
static class User {
private int id;
private String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
}
}
在这个示例中,`Single`用于表示一个可能成功返回单个用户信息或者失败返回错误的场景。`Single`只能发出一个元素(在这个例子中是一个`User`对象)或者一个错误,而不能发出多个元素。
使用`Observable`获取多个用户信息
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;
public class ObservableExample {
public static void main(String[] args) {
// 假设这是一个数据库查询操作,它返回多个用户信息
Observable<User> observableUsers = Observable.create(emitter -> {
// 模拟数据库查询
// 假设我们找到了多个用户
emitter.onNext(new User(1, "John Doe"));
emitter.onNext(new User(2, "Jane Doe"));
emitter.onNext(new User(3, "Bob Smith"));
emitter.onComplete();
});
// 订阅Observable
observableUsers
.subscribeOn(Schedulers.io()) // 指定在IO线程上执行异步操作
.observeOn(Schedulers.computation()) // 指定在计算线程上观察结果
.subscribe(
user -> System.out.println("User found: " + user.getName()), // 处理用户信息
error -> error.printStackTrace(), // 处理错误
() -> System.out.println("All users processed.") // 处理完成
);
}
static class User {
private int id;
private String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
}
}
在这个示例中,`Observable`用于表示一个返回多个用户信息的场景。`Observable`可以发出多个元素(在这个例子中是多个`User`对象),每个元素都通过`onNext`方法发出,直到`onComplete`被调用,表示不会再有更多的元素发出。
对比说明
• 元素数量:`Single`只能发出0个或1个元素,而`Observable`可以发出0个或多个元素。
• 用例:`Single`适用于那些只期望一个结果的操作,如获取单个用户信息。`Observable`适用于那些可能产生多个结果的操作,如获取用户列表。
• 错误处理:`Single`在发出一个元素后或者在失败时只能发出一个错误,而`Observable`可以在发出多个元素的过程中发出多个错误。
• 完成通知:`Single`在发出一个元素或者错误后会发出一个完成通知,而`Observable`在发出所有元素后发出一个完成通知。
通过这两个示例,我们可以看到`Single`和`Observable`在处理元素数量和类型上的根本区别。
6.操作符使用示例
在 RxJava 中,操作符是其强大功能的核心,它们可以用来转换、组合、过滤、处理错误等。以下是一个示例,展示了如何在一个流程中使用多种操作符,包括`map`、`filter`、`flatMap`、`mergeWith`、`concatWith`、`zipWith`、`onErrorResumeNext`、`startWith`和`take`。
示例场景
假设我们有一个用户管理系统,需要从数据库中获取用户信息,然后根据用户的角色过滤用户,接着获取每个用户的详细信息,并将用户信息与他们的订单信息合并,最后输出结果。
以下是完整的代码示例:
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.schedulers.Schedulers;
import java.util.Arrays;
import java.util.List;
public class RxJavaOperatorsExample {
public static void main(String[] args) {
// 模拟从数据库获取用户列表
Observable<User> usersObservable = Observable.fromIterable(getUsersFromDatabase());
// 模拟从数据库获取订单列表
Observable<Order> ordersObservable = Observable.fromIterable(getOrdersFromDatabase());
// 使用操作符处理数据流
usersObservable
.subscribeOn(Schedulers.io()) // 指定在IO线程上执行
.observeOn(Schedulers.computation()) // 指定在计算线程上处理数据
.filter(user -> user.getRole().equals("ADMIN")) // 只处理角色为ADMIN的用户
.map(user -> {
// 模拟获取用户详细信息
user.setDetails(getUserDetails(user.getId()));
return user;
})
.flatMap(user -> {
// 模拟获取用户订单信息
return Observable.fromIterable(getUserOrders(user.getId()))
.map(order -> new UserOrderPair(user, order));
})
.mergeWith(ordersObservable.map(order -> new UserOrderPair(null, order))) // 合并用户订单和独立订单
.zipWith(Observable.interval(1, TimeUnit.SECONDS), (userOrderPair, time) -> {
// 模拟延时处理
return userOrderPair;
})
.take(5) // 只取前5个结果
.startWith(new UserOrderPair(new User(0, "Loading...", ""), new Order(0, "Loading..."))) // 在开始时添加一个占位符
.onErrorResumeNext(error -> {
// 处理错误
System.out.println("Error occurred: " + error.getMessage());
return Observable.empty();
})
.subscribe(
userOrderPair -> {
// 输出结果
if (userOrderPair.getUser() != null) {
System.out.println("User: " + userOrderPair.getUser().getName() +
", Order: " + userOrderPair.getOrder().getDescription());
} else {
System.out.println("Order: " + userOrderPair.getOrder().getDescription());
}
},
error -> error.printStackTrace(),
() -> System.out.println("All data processed.")
);
}
// 模拟从数据库获取用户列表
private static List<User> getUsersFromDatabase() {
return Arrays.asList(
new User(1, "John Doe", "ADMIN"),
new User(2, "Jane Doe", "USER"),
new User(3, "Bob Smith", "ADMIN")
);
}
// 模拟从数据库获取订单列表
private static List<Order> getOrdersFromDatabase() {
return Arrays.asList(
new Order(1, "Order 1"),
new Order(2, "Order 2"),
new Order(3, "Order 3")
);
}
// 模拟获取用户详细信息
private static String getUserDetails(int userId) {
return "Details for user " + userId;
}
// 模拟获取用户订单信息
private static List<Order> getUserOrders(int userId) {
return Arrays.asList(
new Order(1, "Order for user " + userId),
new Order(2, "Another order for user " + userId)
);
}
// 用户类
static class User {
private int id;
private String name;
private String role;
private String details;
public User(int id, String name, String role) {
this.id = id;
this.name = name;
this.role = role;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getRole() {
return role;
}
public void setDetails(String details) {
this.details = details;
}
}
// 订单类
static class Order {
private int id;
private String description;
public Order(int id, String description) {
this.id = id;
this.description = description;
}
public String getDescription() {
return description;
}
}
// 用户订单对
static class UserOrderPair {
private User user;
private Order order;
public UserOrderPair(User user, Order order) {
this.user = user;
this.order = order;
}
public User getUser() {
return user;
}
public Order getOrder() {
return order;
}
}
}
代码解析
• `filter`:过滤出角色为`ADMIN`的用户。
• `map`:将用户信息映射为包含详细信息的用户对象。
• `flatMap`:将每个用户与他们的订单信息组合成一个`UserOrderPair`对象。
• `mergeWith`:将用户订单与独立订单合并。
• `zipWith`:与时间间隔流`Observable.interval`组合,模拟延时处理。
• `take`:只取前5个结果。
• `startWith`:在数据流开始时添加一个占位符。
• `onErrorResumeNext`:处理错误,并在出错时返回一个空的`Observable`。
• `subscribe`:订阅数据流,并处理每个结果。
输出示例
运行程序后,将会输出如下:
Loading...
User: John Doe, Order: Order for user 1
User: John Doe, Order: Another order for user 1
User: Bob Smith, Order: Order for user 3
User: Bob Smith, Order: Another order for user 3
Order: Order 1
All data processed.
总结
这个示例展示了如何在一个数据流中使用多种操作符来处理复杂的业务逻辑。通过组合这些操作符,你可以构建出强大的异步数据处理流程。
4087

被折叠的 条评论
为什么被折叠?



