快速入门-ReactiveX-RxJava

529 阅读11分钟

ReactiveX(Reactive Extensions)是由微软的开发团队在 2012 年左右创建的,最初是为了处理异步编程中的复杂性而设计。ReactiveX 是一种用于异步编程的库,它基于可观察的数据流和推送模型。ReactiveX 提供了一个统一的 API,用于处理异步数据流,允许开发者以声明式的方式处理事件、数据流和异步操作。ReactiveX 及其各种语言实现(如 RxJava)对现代异步编程产生了深远的影响。它为处理复杂的异步数据流提供了统一的模型,简化了开发者的工作。

今天,ReactiveX 和 RxJava 被广泛应用于各类应用程序中,包括移动应用、微服务架构、实时数据处理等领域。RxJava 是 ReactiveX 的 Java 实现,是一个用于处理异步和基于事件的程序的库。它将 ReactiveX 的概念和操作符引入了 Java 生态系统,使得开发者可以轻松地使用函数式编程风格来处理复杂的异步数据流和事件流。

ReactiveX 特点

  • 声明式编程:使用 ReactiveX,你可以用声明式的方式描述你的业务逻辑。你不需要关心数据的传递和处理的具体实现细节,而是关注数据流的变换和处理。

  • 异步数据处理:ReactiveX 处理异步数据流,通过 Observable 对象将数据以推送的方式发送给订阅者。你不需要手动管理线程或处理回调,ReactiveX 处理所有的并发和异步操作。

  • 组合与变换:ReactiveX 提供了丰富的操作符,用于对数据流进行过滤、转换、组合等操作。例如,你可以使用 map、filter、merge 等操作符来对数据流进行处理。

  • 线程控制:ReactiveX 提供了调度器(Schedulers)用于控制代码的执行线程,例如你可以指定在 I/O 线程执行异步操作,或者在主线程中更新 UI。

  • 可读性与可维护性:通过将业务逻辑拆分为一系列可组合的操作符,ReactiveX 可以提高代码的可读性和可维护性,特别是在处理复杂异步逻辑时。

ReactiveX - RxJava 的例子

为了帮助你更好地理解 ReactiveX,让我们看一个简单的例子(使用 RxJava )。假设我们有一个场景,需要进行一系列的网络请求操作,并在获取到所有数据后进行处理。如果没有使用 RxJava,我们可能需要手动处理线程和回调,代码会变得比较复杂。而使用 RxJava 后,代码会变得更简洁和易于维护。

不使用 RxJava 的实现

import java.util.concurrent.*;

// 使用线程池和 Future 来处理异步请求,等待两个网络请求的结果
// 需要手动管理线程池、等待结果、处理异常等操作
public class WithoutRxJava {
    public static void main(String[] args) {
        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(2);

        Future<String> future1 = executor.submit(() -> {
            // 模拟网络请求 1
            Thread.sleep(1000);  // 模拟耗时操作
            return "Response from API 1";
        });

        Future<String> future2 = executor.submit(() -> {
            // 模拟网络请求 2
            Thread.sleep(1000);  // 模拟耗时操作
            return "Response from API 2";
        });

        try {
            // 等待两个请求的结果并进行处理
            String result1 = future1.get();
            String result2 = future2.get();
            System.out.println("Combined Result: " + result1 + " & " + result2);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            executor.shutdown();
        }
    }
}

使用 RxJava 的实现

// 本文章的所有事例都是以 rxjava3 为主

// maven 依赖
<dependency>
    <groupId>io.reactivex.rxjava3</groupId>
    <artifactId>rxjava</artifactId>
    <version>3.0.4</version>
</dependency>

// gradle 依赖
implementation 'io.reactivex.rxjava3:rxjava:3.0.4'
import io.reactivex.rxjava3.core.Observable;

// 使用 Observable.fromCallable 创建异步的 Observable,用于模拟网络请求。
// 使用 zip 操作符将两个 Observable 组合起来,当两个请求都完成时,zip 会将它们的结果合并,并传递给后续处理。
// 订阅结果,并在回调中处理成功和失败的情况。
public class WithRxJava {
    public static void main(String[] args) {
        // 创建 Observable 用于异步网络请求 1
        Observable<String> apiCall1 = Observable.fromCallable(() -> {
            Thread.sleep(1000);  // 模拟耗时操作
            return "测试 1";
        });

        // 创建 Observable 用于异步网络请求 2
        Observable<String> apiCall2 = Observable.fromCallable(() -> {
            Thread.sleep(1000);  // 模拟耗时操作
            return "测试 2";
        });

        // 使用 RxJava 将两个异步操作组合,并处理结果
        Observable.zip(apiCall1, apiCall2, (result1, result2) -> "结果: " + result1 + " & " + result2)
                .subscribe(System.out::println, Throwable::printStackTrace);
    }
}

通过以上对比,我们可以看到使用 RxJava 可以显著简化异步操作的处理,使代码更简洁、易读、易维护。RxJava 提供了强大的操作符和调度机制,让开发者可以更专注于业务逻辑,而不必被复杂的异步处理细节所困扰。

快速实践

代码事例

package cn.com.openboot.dotj.study.rxjava;

import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;

public class RxJavaExample {

    /**
     * 最简单的快速Demo
     */
    public void demo1() {
        Flowable.fromArray(" hello "" world "" welcome "" to "" the "" Rxjava ")
                .subscribe((e) -> System.out.println(e));
    }

    /**
     * 快速构建 Observable 是可观察的对象
     *
     * 对于Observable发出的每个项目,这些转换后的Observable将同步调用订阅它们的任何订阅者的onNext()方法,
     * 然后将调用订阅者的onCompleted()法。
     */
    public void demo2() {
        Observable<String> o = Observable.fromArray("a""b""c");
        Observable<String> o2 = Observable.fromAction(()-> System.out.println("a"));
        Observable<String> o3 = Observable.just("one object");
    }

    /**
     * 创建一个简单的 Observable,它发出一系列字符串
     */
    public void demo3() {
        Observable<String> observable = Observable.just("Hello""RxJava""World");

        // 创建一个 Observer 并订阅 Observable
        observable.subscribe(
                item -> System.out.println("Observer: " + item),   // onNext
                error -> System.err.println("Error: " + error),    // onError
                () -> System.out.println("Completed!")             // onComplete
        );
    }

    /**
     * 使用操作符进行数据处理
     * 操作符是 RxJava 的强大功能,用于对数据流进行变换、过滤和组合。
     */
    public void demo4() {
        Observable<String> observable = Observable.just("Hello""RxJava""World");

        observable.map(String::toUpperCase)       // 将字符串转换为大写
                .filter(s -> s.startsWith("H"))   // 过滤掉不以"H"开头的字符串
                .subscribe(System.out::println);  // Observer onNext 订阅并打印结果
    }

    /**
     * 线程控制(Schedulers)
     * 在异步编程中,线程控制非常重要。RxJava 提供了 Schedulers 来简化线程管理。
     */
    public void demo5() {
        Observable<String> observable = Observable.just("Hello""RxJava""World");

        observable.subscribeOn(Schedulers.io())  // 在 I/O 线程上执行
                .observeOn(Schedulers.single())  // 在单线程上观察结果
                .subscribe(s -> {
                    System.out.println("Received: " + s + " on thread " + Thread.currentThread().getName());
                });

        try {
            Thread.sleep(1000); // 等待所有异步操作完成
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 使用 RxJava 将两个异步操作组合,并处理结果
     */
    public void demo6() {
        // 创建 Observable 用于异步网络请求 1
        Observable<String> apiCall1 = Observable.fromCallable(() -> {
            Thread.sleep(1000);  // 模拟耗时操作
            return "测试 1";
        });

        // 创建 Observable 用于异步网络请求 2
        Observable<String> apiCall2 = Observable.fromCallable(() -> {
            Thread.sleep(1000);  // 模拟耗时操作
            return "测试 2";
        });

        // 使用 RxJava 将两个异步操作组合,并处理结果
        Observable.zip(apiCall1, apiCall2, (result1, result2) -> "结果: " + result1 + " & " + result2)
                .subscribe(System.out::println, Throwable::printStackTrace);
    }

    public static void main(String[] args) {
        RxJavaExample example = new RxJavaExample();
        System.out.println("=================================");
        example.demo1();
        System.out.println("=================================");
        example.demo2();
        System.out.println("=================================");
        example.demo3();
        System.out.println("=================================");
        example.demo4();
        System.out.println("=================================");
        example.demo5();
    }
    
}

关于 RxJava 的版本迭代,已经从 RxJava 1 到 RxJava 2 又到了 3 具体的变化和调整,建议还是直接查询官方文档和历史发布信息。

github.com/ReactiveX/R…

github.com/ReactiveX/R…

github.com/ReactiveX/R…

RxJava 架构设计原理和思想

RxJava 基于 ReactiveX,其核心设计理念和架构原则围绕着响应式编程的四大原则:响应性、弹性、伸缩性 和 消息驱动。设计思想主要是围绕:函数式编程,链式调用,组合和重用,观察者模式,推送模型,迭代器模式等

+-------------------+
|  Observable       |
|  (Data Source)    |
+-------------------+
        |
        v
+-------------------+
|  Operators        |
|  (Transformations)|
+-------------------+
        |
        v
+-------------------+
|  Scheduler        |
|  (Threading)      |
+-------------------+
        |
        v
+-------------------+
|  Observer         |
|  (Data Sink)      |
+-------------------+

核心组件


# Observable

  这是 RxJava 中的核心组件,用于表示一个可以发出一系列数据的流。
  Observable 是异步数据流的抽象,它发出三种类型的通知:
   onNext(发出数据项)
   onError(发出错误)
    onComplete(发出完成信号)

  常用方法:
   create():         创建一个新的 Observable。
   just(T... items): 创建一个发射指定数据项的 Observable。
   fromIterable(Iterable<? extends T> source): 将 Iterable 转换为 Observable。
   map():            将发射的数据转换为另一种类型。
   flatMap():        将发射的数据映射为多个 Observable,并将它们合并成一个 Observable。

# Observer

  这是一个观察者,它订阅 Observable 并响应 Observable 发出的事件。
  Observer 包含三个方法:onNext、onError 和 onComplete,分别对应 Observable 的三个通知类型。

  常用方法:
   onNext(T value): 接收并处理 Observable 发射的数据项。
   onError(Throwable e): 处理 Observable 发射的错误。
   onComplete(): 在 Observable 完成数据发射时调用。

# Flowable

  Flowable 是 Observable 的增强版,支持背压(backpressure),适用于处理大量数据或高速发射数据的场景。背压机制帮助处理速度不匹配的问题,即发射数据的速度快于消费数据的速度。

  常用方法:
   create(FlowableOnSubscribe<T> source, BackpressureStrategy strategy): 创建一个新的 Flowable,指定背压策略。
   buffer(): 将数据分批发射,形成小的 List 或者 Flowable。
   onBackpressureDrop(): 当无法及时处理数据时,丢弃最新的数据。


# Schedulers

  它是 RxJava 中的线程调度器,控制 Observable 事件发出的时间和线程。
  Scheduler 可以用于指定事件在 IO 线程、计算线程或新线程中执行,从而实现异步和并发操作。

  常用调度器:
   Schedulers.io():          IO 密集型任务,如网络请求、文件操作。
   Schedulers.computation(): CPU 密集型任务,如复杂计算。
   Schedulers.newThread():   每次调用都创建一个新线程。
   Schedulers.single():      使用单一线程执行任务。
   AndroidSchedulers.mainThread(): 在 Android 的主线程上执行。

# Disposable

  Disposable 用于管理 Observable 的生命周期,特别是在需要取消订阅时使用。
  通过调用 dispose(),可以停止 Observer 接收 Observable 发射的数据。

  常用方法:
   dispose(): 取消订阅并释放资源。
   isDisposed(): 检查 Disposable 是否已被取消。


# Subject

  Subject 是 Observable 和 Observer 的结合体。
  它既可以订阅其他 Observable,又可以发射数据给订阅者。
  常见的 Subject 类型包括 PublishSubject、BehaviorSubject、ReplaySubject 和 AsyncSubject。

  常见类型:
   PublishSubject:  只向订阅者发射订阅之后的数据。
   BehaviorSubject: 向新订阅者发射最近的一项数据以及后续的数据。
   ReplaySubject:   向所有订阅者发射所有的数据,无论它们何时订阅。
   AsyncSubject:    只发射 Observable 发射的最后一项数据。

# Operators

  RxJava 提供了丰富的操作符用于转换、过滤、组合 Observable 的数据流。
  操作符是 RxJava 中非常强大的一部分,它允许你以声明式的方式定义复杂的数据处理逻辑。

RxJava 的背压(Backpressure)和线程管理:github.com/ReactiveX/R…

总结

RxJava 的实际使用场景

  • 异步网络请求处理:在 Android 应用开发中,RxJava 常用于处理异步网络请求。通过将网络请求封装为 Observable,开发者可以轻松管理多个并发请求、处理响应数据以及管理错误。
  • UI 事件处理(响应式编程):RxJava 可以用来处理用户界面的事件流,例如按钮点击、文本输入等。通过 RxJava,开发者可以将多个 UI 事件合并、过滤或变换,然后统一处理。
  • 复杂数据流转换:RxJava 在处理数据流时非常强大,尤其是需要对数据流进行一系列的转换、过滤、合并等操作时。它常用于流处理、日志聚合、数据分析等场景。
  • 后台任务调度与管理:RxJava 支持异步和并发操作,因此非常适合用于管理和调度后台任务。例如在后台批量处理数据、下载文件或执行复杂的计算任务。

同类产品比较分析    

框架/库优点缺点使用场景实现产品
RxJava- 丰富的操作符库  - 支持异步数据流和事件驱动编程  - 强大的调度和线程管理- 学习曲线陡峭  - 对于简单的异步任务可能过于复杂- Android 应用开发  - 复杂数据流处理  - 异步任务调度Netflix  Retrofit  Android Framework
Project Reactor- 与 Spring WebFlux 深度集成  - 支持背压机制  - 性能优化 - 提供 Mono 和 Flux 类 - 符合 Reactive Streams 标准- 社区生态不如 RxJava  - 学习曲线较高- 操作符相对较少,但更加专注于 Web 应用场景  - 与 Spring 生态系统密切相关- Spring WebFlux  - 高性能 Web 应用  - 响应式微服务架构Spring WebFlux  RSocket  Spring Cloud Gateway
Akka Streams- 基于 Actor 模型,适合分布式系统  - 支持背压机制  - 强大的容错性- 学习曲线陡峭  - 对 JVM 资源消耗较大- 分布式系统  - 高度可扩展的实时数据处理系统Lightbend Platform  Akka HTTP  Akka Cluster
Kotlin Coroutines- 简单易用,集成 Kotlin 语言特性  - 支持结构化并发  - 易于调试- 操作符库相对较少  - 依赖于 Kotlin 语言- Android 开发  - 简单的异步操作  - 协程与非阻塞 I/OAndroid Development  JetBrains Compose
Java 9 FlowJava 标准库的一部分 - 使用门槛低,学习成本较小  - 可以与其他遵循 Reactive Streams 规范的库无缝集成- 功能有限,适用于简单响应式流处理  - 缺少调度器和丰富的操作符- 简单响应式流处理  - 基础响应式编程  - 与其他库结合使用JDK 标准库  Java EE  Spring Framework

致谢

更多内容欢迎点击阅读原文,喜欢文章的话,也希望能给小编点个赞或者转发,你们的喜欢与支持是小编最大的鼓励,小巫编程室感谢您的关注与支持。好好学习,天天向上(good good study day day up)。

  • OPENBOOT[1]
  • ReactiveX[2]
  • ReactiveX 的官网地址[3]
  • ReactiveX - Java 实现开源地址[4]
  • 官方文档[5]

参考资料

[1] OPENBOOT: gitee.com/openboot

[2] ReactiveX: github.com/ReactiveX

[3] ReactiveX 的官网地址: reactivex.io/

[4] ReactiveX - Java 实现开源地址: github.com/ReactiveX/R…

[5] 官方文档: github.com/ReactiveX/R…