RxJava使用和原理(一)

基本介绍

项目源码路径

介绍

  • RxJava(Reactive Extensions for Java)是JVM的一个响应式扩展(ReactiveX)实现。
  • 它通过使用可观察的序列来组合异步和基于事件的程序。

定义与原理

  • RxJava是一个在Java VM上使用可观测的序列来组成异步的、基于事件的程序的库。它扩展了传统的观察者模式,增加了对事件序列的丰富操作和变换能力。
  • 在RxJava中,被观察者(Observable)通过订阅(Subscribe)按顺序发送事件给观察者(Observer),观察者按顺序接收事件并作出对应的响应动作。

核心特性

  • 观察者模式:RxJava的核心思想是观察者模式,它允许对象(被观察者)在状态改变时通知其他对象(观察者)。
  • 丰富的操作符:RxJava提供了一系列的操作符,可以使用它们来过滤、选择、变换、结合和组合多个Observable。这些操作符让执行和复合变得非常高效。
  • 线程切换:RxJava内部提供了多个调度器(Schedulers),如I/O操作调度器(Schedulers.io())、新线- 程调度器(Schedulers.newThread())、默认线程调度器(Schedulers.immediate())和计算所使用的调度器(Schedulers.computation())。开发者可以使用这些调度器来控制Observable在不同线程上的执行。
  • 背压机制:背压是响应式流中的一个重要概念,它允许消费者控制从生产者那里接收数据的速率。RxJava支持背压机制,使得开发者可以更好地处理数据流中的压力。

基本使用

核心概念

  • Observable(被观察者):负责发送事件(数据流)。
  • Observer(观察者):接收事件并处理。
  • Subscriber(订阅者):Observer 的子类,增加了对订阅关系的控制。
  • Scheduler(调度器):用于控制线程切换。

基本使用示例

Observable.create(new ObservableOnSubscribe<String>() {
    @Override
    public void subscribe(ObservableEmitter<String> emitter) throws Exception {
        emitter.onNext("Hello");
        emitter.onNext("RxJava");
        emitter.onComplete();
    }
})
.subscribeOn(Schedulers.io()) // 指定被观察者的执行线程
.observeOn(AndroidSchedulers.mainThread()) // 指定观察者的执行线程
.subscribe(new Observer<String>() {
    @Override
    public void onSubscribe(Disposable d) {
        // 订阅时调用
    }

    @Override
    public void onNext(String s) {
        // 接收到数据时调用
        Log.d("RxJava", s);
    }

    @Override
    public void onError(Throwable e) {
        // 发生错误时调用
    }

    @Override
    public void onComplete() {
        // 数据流结束时调用
    }
});

常用操作符

不同类型的被观察者

Observable

特性:

  • 支持异步操作,可以在后台线程上执行任务,然后将结果发送到前台线程。
  • 基于事件驱动,当有新的数据产生时,会自动通知所有订阅者。
  • 支持多种操作符,可以方便地对数据进行转换、过滤等操作。
  • 可以处理错误,当出现异常时,可以选择继续执行或者终止操作。
  • 可以自动管理资源,例如在订阅时打开资源,在取消订阅时关闭资源。

使用场景:

  • 处理最大不超过1000条数据,并且几乎不会出现内存溢出的情况。
  • 处理同步流。
Flowable

特性:

  • 是RxJava2.x新增的被观察者,用于替代Observable以支持非阻塞式的背压。
  • 可以看作是Observable的新实现,但增加了对背压的支持。
  • 支持并发模式,是JDK9标准接口Reactive Streams的实现。

使用场景:

  • 处理以某种方式产生超过10KB的元素。
  • 文件读取与分析。
  • 读取数据库记录(阻塞的和基于拉取的模式)。
  • 创建一个响应式非阻塞接口。
Single

特性:

  • 只有onSuccess和onError事件。
  • onSuccess()用于发射数据,而且只能发射一个数据,后面即使再发射数据也不会做任何处理。
  • SingleObserver中只有onSuccess和onError,并没有onComplete。

使用场景:

  • 当确定只会发射一个数据项或发生错误时,可以使用Single。
Completable

特性:

  • 在创建后,不会发射任何数据。
  • 只有onComplete和onError事件。
  • 相比Observable/Flowable,操作符要少得多。

使用场景:

  • 当不需要发射数据,只需要知道操作何时完成时,可以使用Completable。
Maybe

特性:

  • 可以看作是Single和Completable的结合。
  • 只能通过onSuccess()方法发射数据,且只能发射0或1个数据。
  • 如果MaybeEmitter先调用了onComplete(),即使后面再调用onSuccess(),也不会发射任何数据。

使用场景:

  • 当不确定是否会发射数据,但希望有一个明确的完成或错误信号时,可以使用Maybe。

操作符

创建操作符

创建操作符用于从头开始创建Observable(被观察者对象)或其他类型的被观察者,并允许观察者的方法被编程调用

create
  • 作用:从头开始创建一个Observable,允许开发者通过编程方式调用观察者的方法(如onNext、onError、onCompleted)。
  • 特点:开发者需要提供一个函数,该函数接受一个Subscriber(或ObservableEmitter)作为参数,并在其中定义事件发送的逻辑。
  • 示例:
Observable.create(new ObservableOnSubscribe<Integer>() {
    @Override
    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
        emitter.onNext(1);
        emitter.onNext(2);
        emitter.onNext(3);
        emitter.onComplete();
    }
}).subscribe(new Observer<Integer>() {
    @Override
    public void onSubscribe(Disposable d) {
        // 开始订阅时的操作
    }
 
    @Override
    public void onNext(Integer value) {
        // 接收到事件时的操作
    }
 
    @Override
    public void onError(Throwable e) {
        // 发生错误时的操作
    }
 
    @Override
    public void onComplete() {
        // 完成时的操作
    }
});
just
  • 作用:快速创建一个Observable,并直接发送传入的事件。
  • 特点:最多只能发送10个参数,适用于快速创建Observable并发送少量事件。
  • 示例:
Observable.just(1, 2, 3, 4).subscribe(new Observer<Integer>() {
    // ...省略订阅逻辑...
});
defer
  • 作用:直到有观察者订阅时,才动态创建Observable并发送事件。
  • 特点:每次订阅都会得到一个新的Observable对象,确保Observable对象里的数据是最新的。
  • 示例:
Observable<Integer> observable = Observable.defer(new Callable<Observable<Integer>>() {
    @Override
    public Observable<Integer> call() throws Exception {
        // 根据条件动态创建Observable
        if (someCondition) {
            return Observable.just(1, 2, 3);
        } else {
            return Observable.just(4, 5, 6);
        }
    }
});
observable.subscribe(new Observer<Integer>() {
    // ...省略订阅逻辑...
});
from
  • 作用:将其他类型的对象或数据结构转换为Observable。
  • 特点:支持将数组、集合、Future等转换为Observable,方便统一处理。
  • 示例:
Integer[] items = {0, 1, 2, 3, 4, 5};
Observable.fromArray(items).subscribe(new Observer<Integer>() {
    // ...省略订阅逻辑...
});
interval
  • 作用:创建一个在指定时间间隔内发射整数的Observable。
  • 特点:通常用于需要定时发送事件的场景。
  • 示例:
Observable.interval(1, TimeUnit.SECONDS).take(5).subscribe(new Observer<Long>() {
    // ...省略订阅逻辑...
});

上述代码会每秒发送一个递增的整数,共发送5个。

range
  • 作用:创建一个以给定范围的整数序列发射的Observable。
  • 特点:适用于需要生成一定范围内整数序列的场景。
  • 示例:
Observable.range(1, 5).subscribe(new Observer<Integer>() {
    // ...省略订阅逻辑...
});

上述代码会发送从1到5的整数序列。

repeat
  • 作用:创建一个重复发射特定数据或数据序列的Observable。
  • 特点:适用于需要重复发送相同数据或数据序列的场景。
  • 示例:
Observable.just("Hello").repeat(3).subscribe(new Observer<String>() {
    // ...省略订阅逻辑...
});

上述代码会重复发送字符串"Hello"三次。

timer
  • 作用:创建一个延迟一段时间后发射单个项的Observable。
  • 特点:通常用于需要延迟发送事件的场景。
  • 示例:
Observable.timer(2, TimeUnit.SECONDS).subscribe(new Observer<Long>() {
    // ...省略订阅逻辑...
});
转换操作符

转换操作符用于对Observable(被观察者对象)发射的数据进行转换,以便观察者能够接收到转换后的数据。

map()
  • 作用:对Observable发射的每一项数据应用一个函数,然后返回一个新的Observable,该Observable发射转换后的数据。
  • 特点:适用于一对一的数据转换场景。
  • 示例:将整数列表中的每个整数转换为它的平方数。
Observable.range(1, 4)
    .map(i -> i * i)
    .subscribe(i -> System.out.println(i)); // 输出:1, 4, 9, 16
flatMap()
  • 作用:将一个发射数据的Observable变换为多个Observables,然后将它们的数据合并后放入一个单独的Observable。
  • 特点:适用于一对多或多对多的数据转换场景,可以处理嵌套的数据结构。
  • 示例:将学生列表中的每个学生的课程列表展平为一个课程列表。
List<Student> students = // ... 学生列表
Observable.from(students)
    .flatMap(student -> Observable.fromIterable(student.getCourses()))
    .subscribe(course -> System.out.println(course.getName()));
concatMap()
  • 作用:与flatMap()类似,但确保转发出来的事件是有序的。
  • 特点:适用于需要保持数据顺序的一对多数据转换场景。
  • 示例:与flatMap()类似,但确保转换后的数据按原始顺序发射。
flatMapIterable()
  • 作用:类似于flatMap(),但转换后的是一个Iterable对象。
  • 特点:适用于将发射的数据项转换为Iterable对象,并将这些Iterable对象的内容合并到一个Observable中发射。
switchMap()
  • 作用:当一个Observable发射一个数据时,使用这个函数将数据映射成一个新的Observable,然后开始发射这个新Observable的数据。如果原始的Observable发射了一个新的数据项,switchMap会取消订阅当前正在发射数据的Observable,并开始发射一个新的Observable的数据。
  • 特点:适用于需要切换Observable的场景,如网络请求的取消和重试。
scan()
  • 作用:对Observable流序列的每一项数据应用一个累积函数,然后将这个函数的累积结果发射出去。
  • 特点:类似于递归操作,可以用于计算累计和、平均值等。
  • 示例:计算1到5的累加和。
Observable.range(1, 5)
    .scan(0, (sum, i) -> sum + i)
    .subscribe(sum -> System.out.println(sum)); // 输出:0, 1, 3, 6, 10, 15(注意第一个输出是初始值0)

注意:在上面的示例中,scan的累积函数接受两个参数:一个是累积的结果(sum),另一个是当前的元素(i)。初始值设置为0。

buffer()
  • 作用:从需要发送的事件当中获取一定数量的事件,并将这些事件放到缓冲区当中一并发出。
  • 特点:适用于需要将多个事件组合成一个事件发射的场景。
window()
  • 作用:类似于buffer(),但window()操作符返回的是Observable<Observable>类型,即它会发射一个Observable,这个Observable又发射原始Observable中的元素。
groupBy()
  • 作用:根据指定的函数对Observable发射的数据进行分组,并返回一个Observable<GroupedObservable<K, T>>,其中K是分组的键,T是原始数据。
  • 特点:适用于需要对数据进行分组处理的场景。
cast()
  • 作用:将源事件类型转换成指定的数据类型。
  • 特点:是map的特殊版本,只能用于将父类对象转换为子类对象。如果转换失败,会抛出ClassCastException异常。
组合操作符

组合操作符用于将多个 Observable(被观察者对象)组合成一个 Observable,以便能够同时处理多个数据源。

concat() 和 concatArray()
  • 作用:组合多个 Observable 一起发送数据,合并后按发送顺序串行执行。
  • 区别:concat() 用于组合数量小于或等于 4 个的 Observable,而 concatArray() 可以组合数量大于 4 个的 Observable。
  • 示例:
Observable.concat(
    Observable.just(1, 2, 3),
    Observable.just(4, 5, 6)
)
.subscribe(integer -> System.out.println("接收到的数据: " + integer));

// 输出将按顺序:1, 2, 3, 4, 5, 6

merge() 和 mergeArray()
  • 作用:组合多个 Observable 一起发送数据,合并后按时间线并行执行。
  • 区别:与 concat() 和 concatArray() 类似,merge() 用于组合数量小于或等于 4 个的 Observable,而 mergeArray() 可以组合数量大于 4 个的 Observable。
  • 特点:合并后的 Observable 可能会让原始 Observables 发射的数据交错。
  • 示例:
Observable.merge(
    Observable.intervalRange(0, 3, 1, 1, TimeUnit.SECONDS),
    Observable.intervalRange(10, 3, 1, 1, TimeUnit.SECONDS)
)
.subscribe(aLong -> System.out.println("接收事件: " + aLong));

// 输出将交错:0, 10, 1, 11, 2, 12…

zip()
  • 作用:将多个 Observable 发射的数据按顺序结合,每个数据只能组合一次,且都是有序的。它只发射与发射数据项最少的那个 Observable 一样多的数据。
  • 特点:具体的结合方式由提供的函数决定。
  • 示例:
Observable.zip(
    Observable.just(1, 2, 3),
    Observable.just('a', 'b', 'c'),
    (integer, c) -> integer + "-" + c
)
.subscribe(s -> System.out.println("zip 结果: " + s));

// 输出:1-a, 2-b, 3-c

combineLatest()
  • 作用:将两个或多个 Observable 产生的结果进行合并,合并的结果组成一个新的 Observable。这两个 Observable 中任意一个 Observable 产生的结果,都和另一个 Observable 最后产生的结果,按照一定的规则进行合并。
  • 特点:只要有一个 Observable 发射数据,combineLatest 就会发射一个合并后的数据项,且每次发射都会基于每个 Observable 的最新数据。
  • 示例:
Observable<Long> observable1 = Observable.timer(0, 1000, TimeUnit.MILLISECONDS)
    .map(aLong -> aLong * 5)
    .take(5);
Observable<Long> observable2 = Observable.timer(500, 1000, TimeUnit.MILLISECONDS)
    .map(aLong -> aLong * 10)
    .take(5);
 
Observable.combineLatest(
    observable1, 
    observable2, 
    (aLong, aLong2) -> aLong + aLong2
)
.subscribe(aLong -> System.out.println("combineLatest 结果: " + aLong));

// 输出将基于两个 Observable 的最新数据进行合并

startWith() 和 startWithArray()
  • 作用:在发送原始 Observable 的数据之前,先发送指定的数据或数据数组。
  • 示例:
Observable.just(2, 3, 4)
    .startWith(1)
    .subscribe(integer -> System.out.println("接收到的数据: " + integer));

// 输出:1, 2, 3, 4

concatDelayError() 和 mergeDelayError()
  • 作用:类似于 concat() 和 merge(),但它们在处理错误时有所不同。这些操作符会延迟错误的传递,直到所有原始 Observable 都完成或遇到错误。
  • 特点:concatDelayError() 按顺序执行,而 mergeDelayError() 并行执行。
join() 和 groupJoin()
  • 作用:基于时间窗口将两个 Observable 发射的数据结合在一起。每个 Observable 在自己的时间窗口内都是有效的,都可以拿来组合。
  • 特点:join() 和 groupJoin() 的参数包括源 Observable、目标 Observable、以及控制每个 Observable 产生结果生命周期和合并规则的函数。
过滤操作符

过滤操作符用于根据特定条件筛选 Observable 发射的数据项。这些操作符允许你定义逻辑来保留或丢弃流中的元素。

filter(Predicate<? super T> predicate):
  • 功能:只保留满足给定谓词(Predicate)条件的元素。
  • 示例:从整数列表中过滤出所有的偶数。
Observable.fromIterable(Arrays.asList(1, 2, 3, 4, 5, 6))
    .filter(x -> x % 2 == 0)
    .subscribe(System.out::println); // 输出: 2, 4, 6
take(long count):
  • 功能:从流中取前 count 个元素。
  • 示例:获取 Observable 发射的前 3 个元素。
Observable.range(1, 10)
    .take(3)
    .subscribe(System.out::println); // 输出: 1, 2, 3
takeLast(long count):
  • 功能:从流中取最后 count 个元素(需要 Observable 完成才能确定)。
  • 示例:获取 Observable 发射的最后 3 个元素。
Observable.range(1, 10)
    .takeLast(3)
    .subscribe(System.out::println); // 输出: 8, 9, 10(在 Observable 完成时)
takeWhile(Predicate<? super T> predicate):
  • 功能:只要元素满足给定条件就继续发射,一旦遇到不满足条件的元素就停止发射。
  • 示例:发射整数直到遇到第一个偶数。
Observable.range(1, 10)
    .takeWhile(x -> x % 2 != 0)
    .subscribe(System.out::println); // 输出: 1(因为 1 是奇数,但 2 不是)
skip(long count):
  • 功能:跳过前 count 个元素,然后发射剩余的元素。
  • 示例:跳过 Observable 发射的前 3 个元素。
Observable.range(1, 10)
    .skip(3)
    .subscribe(System.out::println); // 输出: 4, 5, 6, 7, 8, 9, 10
skipWhile(Predicate<? super T> predicate):
  • 功能:只要元素满足给定条件就继续跳过,一旦遇到不满足条件的元素就开始发射。
  • 示例:跳过所有奇数,然后开始发射偶数。
Observable.range(1, 10)
    .skipWhile(x -> x % 2 != 0)
    .subscribe(System.out::println); // 输出: 2, 4, 6, 8, 10(因为从 2 开始都是偶数)
throttleFirst(long windowDuration, TimeUnit unit) 和 throttleLast(long windowDuration, TimeUnit unit) 等节流操作符:
  • 功能:用于控制发射频率,throttleFirst 保留每个窗口周期内的第一个元素,throttleLast 保留每个窗口周期内的最后一个元素。
  • 示例:每秒钟只保留第一个或最后一个发射的元素。
条件操作符

条件操作符允许通过设置函数来判断被观察者(Observable)发送的事件是否符合特定条件,从而决定如何处理这些事件。

all(Predicate<? super T> predicate):
  • 功能:判断 Observable 发射的所有数据项是否都满足给定的条件。如果所有数据项都满足条件,则返回 true;否则返回 false。
  • 示例:检查一个整数列表中的所有数字是否都小于 10。
Observable.just(1, 2, 3, 4, 5, 6)
    .all(integer -> integer < 10)
    .subscribe(result -> System.out.println("All numbers are less than 10: " + result)); // 输出: All numbers are less than 10: true
contains(Object o):
  • 功能:判断 Observable 发射的数据流中是否包含指定的元素。
  • 示例:检查一个整数列表中是否包含数字 3。
Observable.just(1, 2, 3, 4, 5)
    .contains(3)
    .subscribe(result -> System.out.println("Contains 3: " + result)); // 输出: Contains 3: true
exists(Predicate<? super T> predicate)(或某些版本中的 any(Predicate<? super T> predicate)):
  • 功能:判断 Observable 发射的数据流中是否存在至少一个满足给定条件的元素。如果存在,则返回 true;否则返回 false。
  • 示例:检查一个整数列表中是否存在偶数。
Observable.just(1, 3, 5, 7, 8)
    .any(integer -> integer % 2 == 0)
    .subscribe(result -> System.out.println("Exists even number: " + result)); // 输出: Exists even number: true
isEmpty():
  • 功能:判断 Observable 是否没有发射任何元素。如果 Observable 没有发射元素就完成了,则返回 true;否则返回 false。
  • 示例:检查一个 Observable 是否为空。
Observable.empty()
    .isEmpty()
    .subscribe(result -> System.out.println("Is empty: " + result)); // 输出: Is empty: true
takeWhile(Predicate<? super T> predicate):
  • 功能:只要发射的元素满足给定条件就继续发射,一旦遇到不满足条件的元素就停止发射。
  • 示例:发射整数直到遇到第一个大于或等于 5 的数字。
Observable.range(1, 10)
    .takeWhile(integer -> integer < 5)
    .subscribe(System.out::println); // 输出: 1, 2, 3, 4
takeUntil(Predicate<? super T> predicate) 或 takeUntil(Observable other):
  • 功能:第一个版本是当发射的元素满足给定条件时停止发射;第二个版本是当另一个 Observable 开始发射元素时停止当前 Observable 的发射。
  • 示例:发射整数直到遇到数字 5(使用 Predicate 版本)。
Observable.range(1, 10)
    .takeUntil(integer -> integer == 5)
    .subscribe(System.out::println); // 输出: 1, 2, 3, 4, 5(注意:5 也会被发射,因为条件是“直到”满足时停止)

或者,使用另一个 Observable 来停止发射:

Observable.interval(1, TimeUnit.SECONDS)
    .takeUntil(Observable.timer(5, TimeUnit.SECONDS))
    .subscribe(System.out::println); // 输出: 每秒发射一个数字,直到 5 秒后停止
skipWhile(Predicate<? super T> predicate):
  • 功能:只要发射的元素满足给定条件就继续跳过,一旦遇到不满足条件的元素就开始发射。
  • 示例:跳过所有小于 5 的整数,然后开始发射。
Observable.range(1, 10)
    .skipWhile(integer -> integer < 5)
    .subscribe(System.out::println); // 输出: 5, 6, 7, 8, 9
skipUntil(Observable other):
  • 功能:在另一个 Observable 开始发射元素之前,跳过当前 Observable 发射的所有元素。
  • 示例:跳过所有元素,直到另一个 Observable 开始发射。
Observable.interval(1, TimeUnit.SECONDS)
    .skipUntil(Observable.timer(3, TimeUnit.SECONDS))
    .subscribe(System.out::println); // 前 3 秒发射的元素被跳过,从第 4 秒开始发射
sequenceEqual(Observable other):
  • 功能:比较两个 Observable 发射的元素序列是否相同(包括元素、发射顺序和最终状态)。
  • 示例:比较两个整数序列是否相等。
Observable.just(1, 2, 3)
    .sequenceEqual(Observable.just(1, 2, 3))
    .subscribe(result -> System.out.println("Sequences are equal: " + result)); // 输出: Sequences are equal: true
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值