RxJava 是一个基于观察者模式 、使用可序列化的 响应式扩展(Reactive Extensions) 来实现异步操作 和事件处理的库。它在 Android 开发中尤其擅长处理复杂的异步任务链、线程切换和事件流。
核心概念
-
Observable (被观察者) : 数据源或事件源,负责发射数据或事件。它可以发射零个、一个或多个数据,以及一个成功或错误的状态。
-
Observer (观察者) : 订阅
Observable
并对其发出的事件做出反应。它包含四个方法:onSubscribe(Disposable d)
: 开始订阅时调用,参数Disposable
可用于取消订阅。onNext(T t)
: 接收到一个数据项时调用。onError(Throwable e)
: 当Observable
发生错误时调用。onComplete()
: 当Observable
完成所有数据发射时调用。
-
Operator (操作符) : 用于在
Observable
和Observer
之间对发出的数据流进行转换、过滤、组合等操作。例如map
,filter
,flatMap
等。 -
Scheduler (调度器) : 用于控制线程。指定代码在哪个线程执行(如 IO 线程、计算线程、主线程)。
-
Disposable: 用于取消订阅,防止内存泄漏。
-
Single, Maybe, Completable :
Observable
的特殊变种,用于特定场景。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 强大功能的体现。
-
map() : 转换发射的数据类型。
java
vbnetObservable.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
-
filter() : 过滤数据。
java
typescriptObservable.just(1, 2, 3, 4, 5) .filter(number -> number % 2 == 0) // 只允许偶数通过 .subscribe(number -> Log.d("TAG", "" + number)); // 输出: 2, 4
-
flatMap() : 将一个发射数据的 Observable 变换为多个 Observables,然后将它们扁平化为一个单独的 Observable。非常适合用于链式异步操作(如先请求 A,再用 A 的结果请求 B)。
java
lessObservable.just("user_id_123") .flatMap(userId -> fetchUserDetailsFromNetwork(userId)) // fetchUserDetailsFromNetwork 返回一个 Observable<User> .subscribe(user -> updateUI(user));
-
subscribeOn() & observeOn() : 线程控制的核心。
subscribeOn()
: 指定Observable
在哪个线程执行(即数据发射的线程)。多次调用只有第一次有效。observeOn()
: 指定Observer
在哪个线程接收处理数据(即数据消费的线程)。可以多次调用,改变后续操作的线程。
java
kotlinObservable.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 中,Activity
或 Fragment
被销毁后,如果异步操作还在执行并尝试更新 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 的学习曲线稍陡,但一旦掌握,它能极大地简化异步代码的编写,让逻辑变得清晰且易于维护。先从理解观察者模式 和线程调度开始,然后逐步熟悉常用的操作符。