RxJava 与响应式编程
RxJava 在新项目里常被协程/Flow 替代,但大量老 Android 项目仍在使用。中级面试经常考“你能不能维护老项目,并解释迁移取舍“。
一、响应式编程心智模型
RxJava 把异步事件看成数据流:上游发射、操作符转换、下游订阅、调度器切线程。
二、Observable、Single、Maybe、Completable、Flowable
| 类型 | 含义 | 适用 |
|---|---|---|
| Observable | 0..N 个事件 | UI 事件、普通流 |
| Single | 1 个结果或错误 | 网络请求 |
| Maybe | 0 或 1 个结果 | 缓存查询 |
| Completable | 只关心完成/失败 | 写入、删除 |
| Flowable | 支持背压 | 高频数据流 |
三、调度器与线程切换
subscribeOn 影响上游订阅线程,通常只第一个生效;observeOn 切换下游观察线程,可多次使用。
api.getUser()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(::renderUser, ::showError)
四、常用操作符
- 变换:
map、flatMap、concatMap - 过滤:
filter、distinctUntilChanged - 组合:
zip、combineLatest、merge - 错误:
onErrorReturn、retryWhen - 生命周期:
takeUntil、AutoDispose/RxLifecycle
五、背压与资源释放
背压问题来自上游生产快、下游消费慢。Flowable 可配置 BUFFER、DROP、LATEST 等策略。Android 页面销毁时必须 dispose,否则可能泄漏 Activity。
六、RxJava 与协程/Flow 对比
| 维度 | RxJava | 协程/Flow |
|---|---|---|
| 学习成本 | 高,操作符多 | Kotlin 原生,结构化并发 |
| 取消 | Disposable | Job/coroutine cancellation |
| 背压 | Flowable 专门处理 | Flow 挂起/缓冲操作符 |
| 老项目生态 | 强 | 新项目更主流 |
高频面试题
Q1:subscribeOn 和 observeOn 区别?
答:subscribeOn 决定订阅发生在哪个线程,通常第一个生效;observeOn 决定后续观察者在哪个线程执行,可以多次切换。
Q2:RxJava 为什么容易内存泄漏? 答:订阅链持有 observer/lambda,如果页面销毁后未 dispose,异步结果回来仍可能持有 Activity/View。
Q3:老项目 RxJava 怎么迁移到协程? 答:先从边界层开始,比如 Retrofit 支持 suspend;内部复杂链路可逐步迁移,不要一次性重写全部业务流。
易错点 / 追问
- 不要把所有异步都写成复杂操作符链。
- 不要忘记错误分支,否则链路会终止。
- 不要在主线程做重 map/flatMap 计算。