RxJava 从入门到实战:Android 开发者的异步编程神器

300 阅读5分钟

一、RxJava 是什么?用生活例子秒懂

RxJava 是一个处理异步事件的库,核心思想可以用「观察者模式」和「异步编程」概括。举个生活例子:

  • 观察者模式:就像台灯观察开关,开关(被观察者)动作时(开 / 关),台灯(观察者)会响应(亮 / 灭)。

  • 异步编程:比如你烧水时,不用一直盯着水壶(同步等待),可以去做其他事(异步),水开了(事件触发)再回来处理。

在代码中,RxJava 通过以下核心组件实现这一逻辑:

  • Observable(被观察者) :生产事件(如网络请求结果、按钮点击)。
  • Observer/Subscriber(观察者) :消费事件并处理(如更新 UI、存储数据)。
  • 操作符(Operator) :加工事件(如过滤、转换、合并)。
  • Scheduler(调度器) :控制事件在哪个线程运行(如后台线程请求数据,主线程更新 UI)。

二、RxJava 基础:3 步实现异步操作

以「点击按钮加载图片」为例:

  1. 创建被观察者(Observable)

    java

    // 从网络获取图片URL
    Observable<String> imageUrlObservable = Observable.create(emitter -> {
        String url = network.getImageUrl(); // 模拟网络请求
        emitter.onNext(url); // 发送URL事件
        emitter.onCompleted(); // 事件结束
    });
    
  2. 创建观察者(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();
        }
    };
    
  3. 订阅并设置线程

    java

    imageUrlObservable
        .subscribeOn(Schedulers.io()) // 网络请求在IO线程
        .observeOn(AndroidSchedulers.mainThread()) // UI更新在主线程
        .subscribe(imageSubscriber); // 建立订阅关系
    

三、RxJava 2.0 的重大升级:更清晰的架构

2.0 版本针对 1.x 的痛点做了关键改进:

  1. 背压处理(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
        });
    
  2. 新增观察者类型

    • Single:只处理单个成功事件或错误(如登录结果)。
    • Completable:只处理完成或错误(如数据库操作)。
    • Maybe:兼具 Single 和 Completable 的特性(可能有结果或无结果)。
  3. 操作符和线程优化

    • 操作符返回值更明确(如toList()Observable<List>改为Single<List>)。
    • 移除Schedulers.immediate(),新增Flowable专属操作符。

四、核心操作符:代码的「瑞士军刀」

操作符是 RxJava 的灵魂,能让复杂逻辑变得简洁:

  1. map:数据类型转换

    java

    // 将字符串URL转为Bitmap
    Observable<String> urlObservable = ...;
    urlObservable.map(url -> loadBitmap(url)) // 每个URL转成Bitmap
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(bitmap -> imageView.setImageBitmap(bitmap));
    
  2. flatMap:解决嵌套回调

    java

    // 先获取用户ID,再根据ID获取用户信息
    getUserId()
        .flatMap(id -> getUserInfo(id)) // 嵌套请求转为链式调用
        .subscribe(user -> showUserInfo(user));
    
  3. filter:过滤事件

    java

    // 只处理偶数
    Observable.range(1, 10)
        .filter(num -> num % 2 == 0)
        .subscribe(System.out::println); // 输出2,4,6,8,10
    
  4. throttleFirst:防抖处理

    java

    // 按钮点击防抖(500ms内只响应一次)
    RxView.clicks(button)
        .throttleFirst(500, TimeUnit.MILLISECONDS)
        .subscribe(() -> loadData());
    

五、线程调度:告别 Handler 和 AsyncTask

RxJava 通过subscribeOnobserveOn轻松切换线程:

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 与常用库结合

  1. 与 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));
    
  2. RxBinding 处理 UI 事件

    java

    // 文本变化监听(自动转为Observable)
    RxTextView.textChanges(editText)
        .debounce(300, TimeUnit.MILLISECONDS) // 输入暂停300ms后触发
        .filter(text -> text.length() >= 3) // 至少输入3个字符
        .subscribe(keyword -> search(keyword));
    
  3. 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 等操作符直接实现

八、避坑指南:新手常见问题

  1. 内存泄漏

    • 订阅后必须调用disposable.dispose()取消订阅,推荐用CompositeDisposable管理:

      java

      private CompositeDisposable compositeDisposable = new CompositeDisposable();
      // 订阅时添加到集合
      compositeDisposable.add(observable.subscribe(...));
      // 销毁时取消所有订阅
      @Override protected void onDestroy() {
          compositeDisposable.clear();
          super.onDestroy();
      }
      
  2. 背压处理

    • 处理大数据流时必须使用 Flowable,并调用subscription.request(n)控制数据量。
  3. 操作符选择

    • map用于一对一转换,flatMap用于一对多或嵌套异步,concatMap保证顺序,mergeMap并发处理。

九、总结:RxJava 的核心优势

  • 代码简洁:链式调用避免回调地狱,逻辑更清晰。

  • 线程灵活:一行代码切换线程,无需手动管理 Handler。

  • 功能强大:丰富的操作符(过滤、转换、合并等)应对复杂场景。

  • 社区活跃:与 Retrofit、RxBinding 等库无缝集成,生态完善。

掌握 RxJava,能让你在处理异步任务、复杂逻辑时事半功倍,是 Android 进阶的必备技能!