Android RxJava的使用

RxJava 是一个基于观察者模式 、使用可序列化的 响应式扩展(Reactive Extensions) 来实现异步操作事件处理的库。它在 Android 开发中尤其擅长处理复杂的异步任务链、线程切换和事件流。

核心概念

  1. Observable (被观察者) : 数据源或事件源,负责发射数据或事件。它可以发射零个、一个或多个数据,以及一个成功或错误的状态。

  2. Observer (观察者) : 订阅 Observable 并对其发出的事件做出反应。它包含四个方法:

    • onSubscribe(Disposable d): 开始订阅时调用,参数 Disposable 可用于取消订阅。
    • onNext(T t): 接收到一个数据项时调用。
    • onError(Throwable e): 当 Observable 发生错误时调用。
    • onComplete(): 当 Observable 完成所有数据发射时调用。
  3. Operator (操作符) : 用于在 ObservableObserver 之间对发出的数据流进行转换、过滤、组合等操作。例如 map, filter, flatMap 等。

  4. Scheduler (调度器) : 用于控制线程。指定代码在哪个线程执行(如 IO 线程、计算线程、主线程)。

  5. Disposable: 用于取消订阅,防止内存泄漏。

  6. Single, Maybe, CompletableObservable 的特殊变种,用于特定场景。

    • Single<T>: 只发射一个成功数据或一个错误。
    • Completable: 不发射数据,只关心操作成功或失败。
    • Maybe<T>: 可能发射 0 或 1 个数据,或者一个错误。

基本使用步骤

1. 添加依赖

app/build.gradle 中添加依赖(请查看官网获取最新版本):

gradle

arduino 复制代码
dependencies {
    implementation 'io.reactivex.rxjava3:rxjava:3.1.8'
    implementation 'io.reactivex.rxjava3:rxandroid:3.0.2' // 提供Android主线程调度器

    // 或者,如果你在用 RxJava 2
    // implementation 'io.reactivex.rxjava2:rxjava:2.2.21'
    // implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
}

2. 创建一个 Observable

java

javascript 复制代码
Observable<String> observable = Observable.create(emitter -> {
    // 模拟一些工作,比如网络请求
    try {
        String data = fetchDataFromNetwork();
        emitter.onNext(data); // 发射数据
        emitter.onComplete(); // 发射完成信号
    } catch (Exception e) {
        emitter.onError(e); // 发射错误信号
    }
});

// 使用 just, from, range 等操作符快速创建
Observable.just("Hello", "RxJava"); // 依次发射 "Hello", "RxJava"
Observable.fromArray(new String[]{"A", "B", "C"}); // 从数组发射
Observable.range(1, 5); // 发射 1, 2, 3, 4, 5

3. 创建一个 Observer 并订阅

java

less 复制代码
Observer<String> observer = new Observer<String>() {
    @Override
    public void onSubscribe(@NonNull Disposable d) {
        // 订阅开始,可以在这里保存 Disposable 以便后续取消
        Log.d("RxJava", "onSubscribe");
    }

    @Override
    public void onNext(@NonNull String s) {
        // 处理接收到的数据
        Log.d("RxJava", "onNext: " + s);
    }

    @Override
    public void onError(@NonNull Throwable e) {
        // 处理错误
        Log.e("RxJava", "onError: ", e);
    }

    @Override
    public void onComplete() {
        // 任务完成
        Log.d("RxJava", "onComplete");
    }
};

// 建立订阅关系
observable.subscribe(observer);

4. 使用 Lambda 表达式简化

通常我们会用 Lambda 来简化 Observer 的创建:

java

less 复制代码
Disposable disposable = observable
    .subscribe(
        s -> Log.d("RxJava", "onNext: " + s), // onNext
        throwable -> Log.e("RxJava", "onError: ", throwable), // onError
        () -> Log.d("RxJava", "onComplete") // onComplete
    );

// 保存 disposable,在合适的时候(如 Activity 的 onDestroy)取消订阅
// disposable.dispose();

核心操作符示例

操作符是 RxJava 强大功能的体现。

  1. map() : 转换发射的数据类型。

    java

    vbnet 复制代码
    Observable.just(1, 2, 3)
        .map(number -> "Number is: " + number) // 将 Integer 转换为 String
        .subscribe(s -> Log.d("TAG", s));
    // 输出: Number is: 1, Number is: 2, Number is: 3
  2. filter() : 过滤数据。

    java

    typescript 复制代码
    Observable.just(1, 2, 3, 4, 5)
        .filter(number -> number % 2 == 0) // 只允许偶数通过
        .subscribe(number -> Log.d("TAG", "" + number));
    // 输出: 2, 4
  3. flatMap() : 将一个发射数据的 Observable 变换为多个 Observables,然后将它们扁平化为一个单独的 Observable。非常适合用于链式异步操作(如先请求 A,再用 A 的结果请求 B)。

    java

    less 复制代码
    Observable.just("user_id_123")
        .flatMap(userId -> fetchUserDetailsFromNetwork(userId)) // fetchUserDetailsFromNetwork 返回一个 Observable<User>
        .subscribe(user -> updateUI(user));
  4. subscribeOn() & observeOn() : 线程控制的核心

    • subscribeOn(): 指定 Observable 在哪个线程执行(即数据发射的线程)。多次调用只有第一次有效
    • observeOn(): 指定 Observer 在哪个线程接收处理数据(即数据消费的线程)。可以多次调用,改变后续操作的线程

    java

    kotlin 复制代码
    Observable.create(emitter -> {
            // 在 IO 线程执行(执行耗时操作,如网络请求、读文件)
            String data = doHeavyWork();
            emitter.onNext(data);
            emitter.onComplete();
        })
        .subscribeOn(Schedulers.io()) // 指定上游在 IO 线程执行
        .observeOn(AndroidSchedulers.mainThread()) // 指定下游在主线程接收
        .subscribe(data -> {
            // 在主线程更新 UI
            textView.setText(data);
        });

    Android 中的实践与注意事项

1. 防止内存泄漏:管理 Disposable

在 Android 中,ActivityFragment 被销毁后,如果异步操作还在执行并尝试更新 UI,就会导致内存泄漏或崩溃。必须及时取消订阅。

推荐使用 CompositeDisposable 来管理多个 Disposable

java

scala 复制代码
public class MainActivity extends AppCompatActivity {

    private CompositeDisposable compositeDisposable = new CompositeDisposable();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Disposable disposable = Observable.just("Hello")
                .delay(10, TimeUnit.SECONDS) // 模拟一个长时间运行的任务
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(s -> textView.setText(s));

        // 将 Disposable 添加到 CompositeDisposable 中统一管理
        compositeDisposable.add(disposable);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 在生命周期结束时取消所有订阅
        compositeDisposable.clear(); // 或 compositeDisposable.dispose()
    }
}

2. 与 Retrofit 结合进行网络请求

Retrofit 原生支持返回 Observable 类型,这是最常见的用法。

接口定义:

java

less 复制代码
public interface ApiService {
    @GET("user/{id}")
    Observable<User> getUser(@Path("id") String userId);
}

使用:

java

less 复制代码
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.example.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) // 关键!添加 RxJava 调用适配器
        .build();

ApiService apiService = retrofit.create(ApiService.class);

compositeDisposable.add(
    apiService.getUser("123")
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(
            user -> updateUI(user),
            throwable -> showError(throwable)
        )
);

3. 处理界面事件(RxBinding)

可以使用 RxBinding 库将 Android 的 UI 事件(如点击、文本变化)转换为 Observable。

gradle

arduino 复制代码
implementation 'com.jakewharton.rxbinding4:rxbinding:4.0.0'

java

scss 复制代码
// 监听按钮点击
Disposable clickDisposable = RxView.clicks(button)
        .throttleFirst(500, TimeUnit.MILLISECONDS) // 防止连续点击,500ms内只取第一次
        .subscribe(unit -> {
            // 处理点击事件
            performAction();
        });
compositeDisposable.add(clickDisposable);

// 监听 EditText 文本变化
Disposable textDisposable = RxTextView.textChanges(editText)
        .debounce(300, TimeUnit.MILLISECONDS) // 防抖,停止输入 300ms 后才发射
        .filter(charSequence -> charSequence.length() > 3)
        .subscribe(charSequence -> {
            // 处理搜索建议等
            showSuggestions(charSequence.toString());
        });
compositeDisposable.add(textDisposable);

总结

场景 解决方案
异步任务(网络、数据库) Observable + subscribeOn(Schedulers.io())
更新 UI observeOn(AndroidSchedulers.mainThread())
链式异步任务 flatMap 操作符
事件转换/过滤 map, filter 等操作符
防止内存泄漏 CompositeDisposable 并在生命周期方法中清理
网络请求 Retrofit + RxJava Call Adapter
UI 事件处理 RxBinding 库

RxJava 的学习曲线稍陡,但一旦掌握,它能极大地简化异步代码的编写,让逻辑变得清晰且易于维护。先从理解观察者模式线程调度开始,然后逐步熟悉常用的操作符。

相关推荐
爱笑鱼2 小时前
Binder(八):远端进程死了,BinderProxy 为什么还能收到通知?
android
Android-Flutter2 小时前
Kotlin 冷流与热流详解
android·kotlin
zhangphil2 小时前
Android ContentProvider/ContentResolver读图片,跨进程 IPC慢
android
yueqc12 小时前
Android .so 文件压缩
android·so·包体积
龚礼鹏3 小时前
深入解析 Android Automotive (AAOS) 启动流程与 CarService 核心机制(基于 Android 16 最新源码视角)
android
rosmis3 小时前
agent各指标定义
android·java·开发语言
风样滴男人哟4 小时前
PHP特性之反射类ReflectionClass机制
android·开发语言·php
小孔龙5 小时前
RenderNode 与 DisplayList:Android 硬件加速的绘制记录与复用
android·性能优化
qizayaoshuap5 小时前
鸿蒙 ArkTS 实战:搜索列表 城市实时过滤(示例 94)
android·华为·harmonyos
朝星6 小时前
Framework筑基之Handler消息机制5(应用层)
android