深入浅出安卓RxJava原理

146 阅读4分钟

深入浅出安卓RxJava原理

一、RxJava是什么?——快递公司模型

想象RxJava是一个智能快递公司系统:

  • **你(开发者)**是发货客户
  • 数据是要运送的包裹
  • **Observable(被观察者)**是快递订单
  • **Observer(观察者)**是收件人
  • 操作符是物流中转站(可以对包裹进行加工)
  • **Scheduler(调度器)**是物流路线规划员

二、核心工作原理:观察者模式升级版

1. 基本流程

// 1. 创建快递订单(被观察者)
Observable<String> order = Observable.create(emitter -> {
    emitter.onNext("包裹1"); // 发出包裹
    emitter.onNext("包裹2");
    emitter.onComplete();  // 配送完成
});

// 2. 客户签收(观察者)
Observer<String> customer = new Observer<String>() {
    @Override
    public void onNext(String s) {
        System.out.println("收到:" + s); // 处理包裹
    }
    
    @Override
    public void onComplete() {
        System.out.println("所有包裹已送达");
    }
};

// 3. 建立订阅关系(下单)
order.subscribe(customer);

2. 关键角色解析

组件作用生活类比
Observable数据生产者快递发货方
Observer数据消费者收件人
subscribe建立连接下单
onNext发送数据派送包裹
onComplete完成通知配送完成
onError错误处理包裹丢失通知

三、线程控制原理——物流调度中心

RxJava最强大的特性之一:轻松切换线程

1. 调度器类型

Observable.create(...)
    .subscribeOn(Schedulers.io())     // 发货仓库(IO线程)
    .observeOn(AndroidSchedulers.mainThread()) // 送货上门(主线程)
    .subscribe(...);
调度器用途对应线程
Schedulers.io()网络/文件操作IO线程池
Schedulers.computation()计算任务CPU核心数线程池
AndroidSchedulers.mainThread()UI更新主线程
Schedulers.newThread()普通后台任务新建线程

2. 线程切换原理

RxJava内部通过Handler+ExecutorService实现:

  • subscribeOn:指定上游执行的线程池
  • observeOn:改变下游执行的线程

就像

  • 快递从上海仓库发出(io线程)
  • 在北京中转站换车(observeOn切换)
  • 最后用电动车派送(主线程)

四、操作符原理——物流加工流水线

1. 常见操作符示例

Observable.fromIterable(list) // 源头发货
    .filter(item -> item.price > 100) // 质检过滤
    .map(item -> item.name)   // 重新包装
    .take(5)    // 限量发货
    .subscribe(...); // 最终收货

2. 操作符实现原理

每个操作符都会创建一个新的Observable,形成链式调用:

// 简化版map操作符实现
public final <R> Observable<R> map(Function<T, R> mapper) {
    return new Observable<R>() {
        @Override
        protected void subscribeActual(Observer<? super R> observer) {
            // 创建中间观察者
            source.subscribe(new Observer<T>() {
                @Override
                public void onNext(T t) {
                    // 关键转换代码
                    observer.onNext(mapper.apply(t));
                }
            });
        }
    };
}

就像:每个中转站都会拆开包裹,按规则重新包装后再发出

五、背压(Backpressure)——物流爆仓问题

当发货速度 >> 收货速度时,会出现内存溢出(OOM)

1. 解决方案

// 使用Flowable处理背压
Flowable.range(1, 1000000)
    .onBackpressureBuffer()  // 缓冲策略
    .subscribe(...);

2. 背压策略

策略行为类比
BUFFER缓存所有数据租临时仓库
DROP丢弃超量数据拒收新包裹
LATEST保留最新数据只留最新包裹

六、Disposable——快递订单取消

// 订阅时获得Disposable
Disposable disposable = observable.subscribe(...);

// 需要时取消订阅(避免内存泄漏)
disposable.dispose();

原理:内部通过一个原子布尔标志位isDisposed控制

七、RxJava与LiveData对比

特性RxJavaLiveData
线程切换灵活支持所有线程自动切主线程
生命周期感知需要手动管理自动感知
操作符丰富强大简单有限
学习曲线陡峭平缓
适用场景复杂数据流UI数据观察

八、最佳实践

  1. 内存泄漏防护
// 在Activity中使用
private CompositeDisposable bag = new CompositeDisposable();

void someMethod() {
    bag.add(observable.subscribe(...));
}

@Override
protected void onDestroy() {
    bag.clear(); // 统一清理
    super.onDestroy();
}
  1. 错误处理
.subscribe(
    item -> {...}, // onNext
    throwable -> { // onError
        Log.e("RxJava", "出错啦", throwable);
    }
);
  1. 调试技巧
Observable.range(1, 5)
    .doOnNext(i -> Log.d("TAG", "发射:" + i))
    .subscribe(...);

九、原理总结

RxJava的核心设计思想:

  1. 观察者模式:建立生产者-消费者关系
  2. 装饰器模式:操作符层层包装
  3. 响应式编程:数据流驱动
  4. 函数式编程:无副作用、链式调用

工作流程比喻:

  1. 创建订单(Observable.create)
  2. 添加物流方案(操作符+调度器)
  3. 客户下单(subscribe)
  4. 开始发货(onNext)
  5. 异常处理/完成通知(onError/onComplete)

记住三个关键:

  1. Observable是冷的:不订阅不执行(像未下单不发货)
  2. 操作符会创建新Observable:每个中转站都是独立环节
  3. 线程切换要明确:物流路线规划好才不会送错地方

掌握了RxJava原理,你就能优雅地处理各种异步事件流,让代码像物流系统一样高效有序!