本文深入讲解ReactiveX旗下的RxJava框架,从核心概念到实战应用,帮助你掌握响应式编程的精髓。
一、引言:为什么选择RxJava
在现代软件开发中,异步编程已成为必不可少的技能。传统的回调、线程管理复杂等问题一直困扰着开发者。RxJava(Reactive Extensions for Java)提供了一种优雅的解决方案,让异步编程变得简单而强大。
RxJava的核心优势
声明式编程 - 以数据流的方式描述业务逻辑
链式调用 - 操作符组合,代码简洁易读
强大的操作符 - 100+操作符满足各种场景
线程调度灵活 - 轻松切换执行线程
错误处理优雅 - 统一的异常处理机制
背压支持 - Flowable处理数据流速控制
二、核心架构解析
RxJava基于观察者模式,采用响应式编程思想,核心由四大组件构成。

核心组件详解
Observable(被观察者)
数据源,负责发射数据流。Observable是整个响应式流的起点,它负责产生数据并发送给订阅者。
scss
publicabstractclassObservable<T>
implementsObservableSource<T> {
publicfinalvoidsubscribe(
Observer<? super T> observer) {
subscribeActual(observer);
}
protectedabstractvoidsubscribeActual(
Observer<? super T> observer);
}
Observer(观察者)
数据消费者,接收并处理数据。Observer定义了四个核心方法来处理数据流的不同状态。
csharp
public interface Observer<T> {
// 订阅开始
void onSubscribe(Disposable d);
// 接收数据
void onNext(T t);
// 发生错误
void onError(Throwable e);
// 完成
void onComplete();
}
Operators(操作符)
用于转换、过滤、组合数据流的中间操作。操作符是RxJava的精髓,提供了丰富的数据处理能力。
Schedulers(调度器)
控制Observable和Observer在哪个线程执行,实现灵活的线程调度。
数据流类型
RxJava 3提供了5种主要的数据流类型,每种类型适用于不同的场景:
vbnet
Observable - 发射0到N个数据项,不支持背压,适用于通用场景
Flowable - 发射0到N个数据项,支持背压,适用于大数据量场景
Single - 只发射1个数据项,适用于单一结果场景如网络请求
Maybe - 发射0或1个数据项,适用于可能有结果的场景
Completable - 不发射数据,只关心完成状态
三、快速上手:基础用法
创建Observable的多种方式
方式1:just - 发射固定的数据项
arduino
Observable<String> observable1 =
Observable.just("Hello", "RxJava");
方式2:from - 从数组或集合创建
ini
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Observable<Integer> observable2 =
Observable.fromIterable(numbers);
方式3:create - 自定义发射逻辑
ini
Observable<String> observable3 =
Observable.create(emitter -> {
emitter.onNext("Data 1");
emitter.onNext("Data 2");
emitter.onComplete();
});
方式4:interval - 定时发射
ini
Observable<Long> observable4 =
Observable.interval(1, TimeUnit.SECONDS);
方式5:range - 发射一系列整数
ini
Observable<Integer> observable5 =
Observable.range(1, 10);
订阅Observable
完整的订阅示例:
typescript
Observable.just("Apple", "Banana", "Orange")
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
System.out.println("开始订阅");
}
@Override
public void onNext(String item) {
System.out.println("收到数据: " + item);
}
@Override
public void onError(Throwable e) {
System.err.println("发生错误: "
+ e.getMessage());
}
@Override
public void onComplete() {
System.out.println("完成");
}
});
输出结果:
makefile
开始订阅收到数据: Apple收到数据: Banana收到数据: Orange完成
简化的订阅方式
实际开发中,我们经常使用Lambda表达式简化订阅代码:
go
// 只处理onNext
Observable.just(1, 2, 3)
.subscribe(item -> System.out.println(item));
// 处理onNext和onError
Observable.just(1, 2, 3)
.subscribe(
item -> System.out.println(item),
error -> System.err.println(error)
);
// 处理onNext、onError和onComplete
Observable.just(1, 2, 3)
.subscribe(
item -> System.out.println(item),
error -> System.err.println(error),
() -> System.out.println("完成")
);
四、操作符详解:数据变换的艺术
操作符是RxJava的核心,掌握常用操作符是使用RxJava的关键。

创建操作符
创建操作符用于生成Observable数据源:
scss
// just - 发射预定义的数据项
Observable.just(1, 2, 3);
// fromArray - 从数组创建
Integer[] array = {1, 2, 3, 4, 5};
Observable.fromArray(array);
// fromCallable - 延迟执行
Observable.fromCallable(() -> {
// 只有订阅时才执行
return expensiveOperation();
});
// defer - 为每个订阅者创建新的Observable
Observable.defer(() ->
Observable.just(System.currentTimeMillis()));
转换操作符
map - 一对一转换
最常用的转换操作符,将每个数据项转换为另一种形式:
scss
Observable.just(1, 2, 3, 4, 5)
.map(number -> number * 2)
.subscribe(System.out::println);
// 输出: 2, 4, 6, 8, 10
flatMap - 一对多转换并合并
适用于需要为每个数据项发起异步操作的场景:
kotlin
// 场景:搜索用户并获取每个用户的订单
Observable.just("user1", "user2", "user3")
.flatMap(userId -> {
// 为每个用户发起网络请求
return getUserOrders(userId);
})
.subscribe(order ->
System.out.println(order));
concatMap - 顺序的flatMap
当需要保证执行顺序时使用concatMap:
scss
Observable.just(1, 2, 3)
.concatMap(i -> Observable.just(i * 10)
.delay(100, TimeUnit.MILLISECONDS))
.subscribe(System.out::println);
// 输出严格按顺序: 10, 20, 30
过滤操作符
过滤操作符用于筛选数据流中的数据:
scss
// filter - 过滤数据
Observable.range(1, 10)
.filter(number -> number % 2 == 0)
.subscribe(System.out::println);
// 输出: 2, 4, 6, 8, 10
// take - 只取前N个
Observable.range(1, 100)
.take(5)
.subscribe(System.out::println);
// 输出: 1, 2, 3, 4, 5
// skip - 跳过前N个
Observable.range(1, 10)
.skip(5)
.subscribe(System.out::println);
// 输出: 6, 7, 8, 9, 10
// distinct - 去重
Observable.just(1, 2, 2, 3, 3, 4)
.distinct()
.subscribe(System.out::println);
// 输出: 1, 2, 3, 4
debounce - 防抖(搜索框常用)
在用户停止输入一段时间后才触发搜索,避免频繁请求:
scss
Observable.create(emitter -> {
emitter.onNext("a");
Thread.sleep(100);
emitter.onNext("ab");
Thread.sleep(100);
emitter.onNext("abc");
Thread.sleep(500); // 停顿超过300ms
emitter.onComplete();
})
.debounce(300, TimeUnit.MILLISECONDS)
.subscribe(System.out::println);
// 只输出: abc
组合操作符
组合操作符用于合并多个数据源:
ini
// merge - 合并多个Observable
Observable<String> obs1 = Observable.just("A", "B");
Observable<String> obs2 = Observable.just("C", "D");
Observable.merge(obs1, obs2)
.subscribe(System.out::println);
// 输出: A, B, C, D(顺序不保证)
// zip - 组合对应位置的数据
Observable<Integer> numbers =
Observable.just(1, 2, 3);
Observable<String> letters =
Observable.just("A", "B", "C");
Observable.zip(numbers, letters,
(number, letter) -> number + letter)
.subscribe(System.out::println);
// 输出: 1A, 2B, 3C
// combineLatest - 任一数据源变化时组合最新值
Observable<Long> timer1 =
Observable.interval(1, TimeUnit.SECONDS);
Observable<Long> timer2 =
Observable.interval(2, TimeUnit.SECONDS);
Observable.combineLatest(timer1, timer2,
(t1, t2) -> "T1:" + t1 + " T2:" + t2)
.subscribe(System.out::println);
错误处理操作符
优雅的错误处理是RxJava的一大优势:
php
// onErrorReturn - 错误时返回默认值
Observable.create(emitter -> {
emitter.onNext(1);
emitter.onNext(2);
emitter.onError(new Exception("出错了"));
})
.onErrorReturn(throwable -> -1)
.subscribe(System.out::println);
// 输出: 1, 2, -1
// onErrorResumeNext - 错误时切换到另一个Observable
Observable.create(emitter -> {
emitter.onNext("A");
emitter.onError(new Exception("出错"));
})
.onErrorResumeNext(Observable.just("B", "C"))
.subscribe(System.out::println);
// 输出: A, B, C
// retry - 重试
AtomicInteger count = new AtomicInteger(0);
Observable.create(emitter -> {
int attempt = count.incrementAndGet();
System.out.println("尝试次数: " + attempt);
if (attempt < 3) {
emitter.onError(new Exception("失败"));
} else {
emitter.onNext("成功");
emitter.onComplete();
}
})
.retry(3)
.subscribe(System.out::println);
五、线程调度:掌控异步执行
合理的线程调度是保证应用性能的关键。

Schedulers类型
RxJava提供了多种调度器,每种适用于不同的场景:
Schedulers.io() - IO密集型任务
适用于网络请求、文件读写等IO操作:
scss
Observable.fromCallable(() -> {
// 网络请求、文件读写
return downloadFile();
})
.subscribeOn(Schedulers.io())
.subscribe(result -> System.out.println(result));
Schedulers.computation() - 计算密集型
适用于CPU密集型计算:
scss
Observable.range(1, 1000000)
.map(i -> i * i)
.subscribeOn(Schedulers.computation())
.subscribe();
Schedulers.newThread() - 每次创建新线程
scss
Observable.just(1)
.subscribeOn(Schedulers.newThread())
.subscribe();
Schedulers.single() - 单线程执行
scss
Observable.just(1, 2, 3)
.subscribeOn(Schedulers.single())
.subscribe();
AndroidSchedulers.mainThread() - Android主线程
在Android开发中更新UI时使用:
arduino
Observable.just("更新UI")
.observeOn(AndroidSchedulers.mainThread())
.subscribe(text -> textView.setText(text));
subscribeOn vs observeOn
理解这两个方法的区别是掌握线程调度的关键:
less
Observable.just(1, 2, 3)
.subscribeOn(Schedulers.io())
// 指定数据源在IO线程
.map(number -> {
System.out.println("map线程: " +
Thread.currentThread().getName());
return number * 2;
})
.observeOn(Schedulers.computation())
// 切换到计算线程
.filter(number -> {
System.out.println("filter线程: " +
Thread.currentThread().getName());
return number > 2;
})
.observeOn(Schedulers.newThread())
// 再次切换线程
.subscribe(number -> {
System.out.println("subscribe线程: " +
Thread.currentThread().getName());
System.out.println("结果: " + number);
});
关键区别:
scss
subscribeOn - 指定Observable自身在哪个线程执行(只有第一次有效)
observeOn - 指定后续操作在哪个线程执行(可多次使用)
六、实战应用:结合Retrofit

网络请求 - 结合Retrofit
API接口定义:
less
public interface ApiService {
@GET("users/{id}")
Single<User> getUser(@Path("id") int userId);
@GET("users/{id}/posts")
Observable<List<Post>> getUserPosts(
@Path("id") int userId);
}
Retrofit配置:
csharp
public class NetworkModule {
private static ApiService apiService;
public static ApiService getApiService() {
if (apiService == null) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(
GsonConverterFactory.create())
.addCallAdapterFactory(
RxJava3CallAdapterFactory.create())
.build();
apiService = retrofit.create(ApiService.class);
}
return apiService;
}
}
使用示例:
java
public class UserRepository {
private final ApiService apiService;
private final CompositeDisposable disposables =
new CompositeDisposable();
public UserRepository() {
this.apiService = NetworkModule.getApiService();
}
// 获取用户信息
public void loadUser(int userId,
Consumer<User> onSuccess,
Consumer<Throwable> onError) {
Disposable disposable = apiService.getUser(userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(onSuccess, onError);
disposables.add(disposable);
}
// 清理订阅
public void clear() {
disposables.clear();
}
}
搜索防抖
实现智能搜索,避免频繁请求:
scss
public class SearchActivity extends AppCompatActivity {
private EditText searchEditText;
private final CompositeDisposable disposables =
new CompositeDisposable();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
searchEditText =
findViewById(R.id.search_edit_text);
// 监听搜索框输入
Disposable disposable =
RxTextView.textChanges(searchEditText)
.debounce(500, TimeUnit.MILLISECONDS)
// 防抖500ms
.filter(text -> text.length() >= 2)
// 至少2个字符
.distinctUntilChanged()
// 内容变化才触发
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(text -> {
// 执行搜索
performSearch(text.toString());
});
disposables.add(disposable);
}
private void performSearch(String keyword) {
apiService.search(keyword)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
results -> updateSearchResults(results),
error -> showError(error)
);
}
@Override
protected void onDestroy() {
super.onDestroy();
disposables.clear(); // 防止内存泄漏
}
}
多数据源合并
同时加载多个数据源,等待全部完成后统一处理:
scss
public class HomeRepository {
// 同时加载多个数据源
public Single<HomeData> loadHomeData() {
Single<User> userSingle =
apiService.getCurrentUser();
Single<List<Post>> postsSingle =
apiService.getLatestPosts();
Single<List<Notification>> notificationsSingle =
apiService.getNotifications();
return Single.zip(userSingle,
postsSingle,
notificationsSingle,
(user, posts, notifications) ->
new HomeData(user, posts, notifications))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
}

定时刷新
实现自动刷新功能:
typescript
public class RefreshManager {
private Disposable refreshDisposable;
// 每30秒自动刷新
public void startAutoRefresh(Runnable refreshAction) {
refreshDisposable =
Observable.interval(30, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(tick -> refreshAction.run());
}
public void stopAutoRefresh() {
if (refreshDisposable != null &&
!refreshDisposable.isDisposed()) {
refreshDisposable.dispose();
}
}
}
七、最佳实践:避坑指南

管理订阅 - 使用CompositeDisposable
正确做法:
scala
public class MyActivity extends AppCompatActivity {
private final CompositeDisposable disposables =
new CompositeDisposable();
private void loadData() {
Disposable disposable = observable
.subscribe(data -> process(data));
disposables.add(disposable);
}
@Override
protected void onDestroy() {
super.onDestroy();
disposables.clear(); // 清理所有订阅
}
}
统一的错误处理
创建一个统一的错误处理器:
java
public class RxErrorHandler {
public static Consumer<Throwable> handleError() {
return throwable -> {
if (throwable instanceof IOException) {
// 网络错误
showToast("网络连接失败");
} else if (throwable instanceof HttpException) {
// HTTP错误
int code =
((HttpException) throwable).code();
showToast("服务器错误: " + code);
} else {
// 其他错误
showToast("发生未知错误");
}
// 记录日志
Log.e("RxError", "Error occurred", throwable);
};
}
}
// 使用
observable.subscribe(
data -> process(data),
RxErrorHandler.handleError()
);
操作符选择
根据场景选择合适的操作符:
less
// flatMap - 不保证顺序,适合并发
Observable.just("A", "B", "C")
.flatMap(item -> processAsync(item))
.subscribe();
// concatMap - 保证顺序,适合顺序执行
Observable.just("A", "B", "C")
.concatMap(item -> processAsync(item))
.subscribe();
// switchMap - 只保留最新的,适合搜索
searchObservable
.switchMap(keyword -> apiService.search(keyword))
.subscribe();
背压处理
处理大数据量时使用Flowable:
scss
Flowable.range(1, 1000000)
.onBackpressureBuffer(100) // 缓冲区
.observeOn(Schedulers.computation(), false, 10)
.subscribe(
data -> process(data),
error -> handleError(error)
);
// 背压策略
Flowable.create(emitter -> {
for (int i = 0; i < 10000; i++) {
emitter.onNext(i);
}
emitter.onComplete();
}, BackpressureStrategy.DROP) // 丢弃策略
.subscribe();
八、总结
RxJava核心要点
响应式思维 - 以数据流的方式思考问题
操作符链 - 灵活组合操作符完成复杂逻辑
线程调度 - 合理使用subscribeOn和observeOn
订阅管理 - 及时dispose避免内存泄漏
错误处理 - 使用专门的错误处理操作符
背压控制 - 大数据量场景使用Flowable