一、RxJava 是什么?用生活例子秒懂
RxJava 是一个处理异步事件的库,核心思想可以用「观察者模式」和「异步编程」概括。举个生活例子:
-
观察者模式:就像台灯观察开关,开关(被观察者)动作时(开 / 关),台灯(观察者)会响应(亮 / 灭)。
-
异步编程:比如你烧水时,不用一直盯着水壶(同步等待),可以去做其他事(异步),水开了(事件触发)再回来处理。
在代码中,RxJava 通过以下核心组件实现这一逻辑:
- Observable(被观察者) :生产事件(如网络请求结果、按钮点击)。
- Observer/Subscriber(观察者) :消费事件并处理(如更新 UI、存储数据)。
- 操作符(Operator) :加工事件(如过滤、转换、合并)。
- Scheduler(调度器) :控制事件在哪个线程运行(如后台线程请求数据,主线程更新 UI)。
二、RxJava 基础:3 步实现异步操作
以「点击按钮加载图片」为例:
-
创建被观察者(Observable)
java
// 从网络获取图片URL Observable<String> imageUrlObservable = Observable.create(emitter -> { String url = network.getImageUrl(); // 模拟网络请求 emitter.onNext(url); // 发送URL事件 emitter.onCompleted(); // 事件结束 }); -
创建观察者(Subscriber)
java
Subscriber<String> imageSubscriber = new Subscriber<String>() { @Override public void onNext(String url) { Bitmap bitmap = loadBitmap(url); // 加载图片 imageView.setImageBitmap(bitmap); // 更新UI } @Override public void onCompleted() {} @Override public void onError(Throwable e) { e.printStackTrace(); } }; -
订阅并设置线程
java
imageUrlObservable .subscribeOn(Schedulers.io()) // 网络请求在IO线程 .observeOn(AndroidSchedulers.mainThread()) // UI更新在主线程 .subscribe(imageSubscriber); // 建立订阅关系
三、RxJava 2.0 的重大升级:更清晰的架构
2.0 版本针对 1.x 的痛点做了关键改进:
-
背压处理(Backpressure)
- 1.x 中 Observable 无法处理大数据流,可能导致 OOM(内存溢出)。
- 2.0 引入Flowable,通过
Subscription.request(n)让观察者控制数据接收量,避免内存压力。
java
Flowable.range(0, 1000) // 生成1000个数字 .subscribe(new Subscriber<Integer>() { private Subscription sub; @Override public void onSubscribe(Subscription s) { sub = s; sub.request(10); // 先请求10个数据 } @Override public void onNext(Integer num) { // 处理数据后再请求下一批 sub.request(10); } // 省略onError和onCompleted }); -
新增观察者类型
- Single:只处理单个成功事件或错误(如登录结果)。
- Completable:只处理完成或错误(如数据库操作)。
- Maybe:兼具 Single 和 Completable 的特性(可能有结果或无结果)。
-
操作符和线程优化
- 操作符返回值更明确(如
toList()从Observable<List>改为Single<List>)。 - 移除
Schedulers.immediate(),新增Flowable专属操作符。
- 操作符返回值更明确(如
四、核心操作符:代码的「瑞士军刀」
操作符是 RxJava 的灵魂,能让复杂逻辑变得简洁:
-
map:数据类型转换
java
// 将字符串URL转为Bitmap Observable<String> urlObservable = ...; urlObservable.map(url -> loadBitmap(url)) // 每个URL转成Bitmap .observeOn(AndroidSchedulers.mainThread()) .subscribe(bitmap -> imageView.setImageBitmap(bitmap)); -
flatMap:解决嵌套回调
java
// 先获取用户ID,再根据ID获取用户信息 getUserId() .flatMap(id -> getUserInfo(id)) // 嵌套请求转为链式调用 .subscribe(user -> showUserInfo(user)); -
filter:过滤事件
java
// 只处理偶数 Observable.range(1, 10) .filter(num -> num % 2 == 0) .subscribe(System.out::println); // 输出2,4,6,8,10 -
throttleFirst:防抖处理
java
// 按钮点击防抖(500ms内只响应一次) RxView.clicks(button) .throttleFirst(500, TimeUnit.MILLISECONDS) .subscribe(() -> loadData());
五、线程调度:告别 Handler 和 AsyncTask
RxJava 通过subscribeOn和observeOn轻松切换线程:
java
Observable.create(emitter -> {
// 耗时操作在IO线程(由subscribeOn指定)
String data = db.query(); // 数据库查询
emitter.onNext(data);
})
.subscribeOn(Schedulers.io()) // 被观察者在IO线程运行
.observeOn(AndroidSchedulers.mainThread()) // 观察者在主线程运行
.subscribe(data -> textView.setText(data));
-
关键规则:
subscribeOn:指定被观察者(如网络请求)的线程,可多次调用但仅第一次有效。observeOn:指定后续操作的线程,可多次调用(每次切换后续逻辑的线程)。
六、实战场景:RxJava 与常用库结合
-
与 Retrofit 结合(网络请求)
java
// Retrofit接口定义 @GET("user/{id}") Observable<User> getUser(@Path("id") String userId); // 使用RxJava处理 api.getUser("123") .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(user -> showUserProfile(user)); -
RxBinding 处理 UI 事件
java
// 文本变化监听(自动转为Observable) RxTextView.textChanges(editText) .debounce(300, TimeUnit.MILLISECONDS) // 输入暂停300ms后触发 .filter(text -> text.length() >= 3) // 至少输入3个字符 .subscribe(keyword -> search(keyword)); -
RxBus 替代 EventBus
java
// 发布事件 RxBus.getInstance().post(new LoginEvent(true)); // 订阅事件 RxBus.getInstance().toObservable(LoginEvent.class) .observeOn(AndroidSchedulers.mainThread()) .subscribe(event -> updateUI(event.isLogin()));
七、为什么选择 RxJava?对比传统方案
| 场景 | 传统方案(Handler/AsyncTask) | RxJava 方案 |
|---|---|---|
| 网络请求 + UI 更新 | 嵌套 Callback,代码混乱(回调地狱) | 链式调用,逻辑清晰 |
| 多任务串行处理 | 手动控制任务顺序,易出错 | flatMap 轻松串联任务 |
| 复杂线程切换 | 手动调用 Handler.post (),代码冗余 | observeOn/subscribeOn 一行切换,支持多次切换 |
| 事件防抖 / 节流 | 自定义定时器或计数器 | throttleFirst/debounce 等操作符直接实现 |
八、避坑指南:新手常见问题
-
内存泄漏
-
订阅后必须调用
disposable.dispose()取消订阅,推荐用CompositeDisposable管理:java
private CompositeDisposable compositeDisposable = new CompositeDisposable(); // 订阅时添加到集合 compositeDisposable.add(observable.subscribe(...)); // 销毁时取消所有订阅 @Override protected void onDestroy() { compositeDisposable.clear(); super.onDestroy(); }
-
-
背压处理
- 处理大数据流时必须使用 Flowable,并调用
subscription.request(n)控制数据量。
- 处理大数据流时必须使用 Flowable,并调用
-
操作符选择
map用于一对一转换,flatMap用于一对多或嵌套异步,concatMap保证顺序,mergeMap并发处理。
九、总结:RxJava 的核心优势
-
代码简洁:链式调用避免回调地狱,逻辑更清晰。
-
线程灵活:一行代码切换线程,无需手动管理 Handler。
-
功能强大:丰富的操作符(过滤、转换、合并等)应对复杂场景。
-
社区活跃:与 Retrofit、RxBinding 等库无缝集成,生态完善。
掌握 RxJava,能让你在处理异步任务、复杂逻辑时事半功倍,是 Android 进阶的必备技能!