RxJava案例

wen java案例 2

5个RxJava案例教你优雅处理异步任务

目录导读

  1. RxJava为何仍是异步编程利器?
  2. 网络请求自动重试(RetryWhen)
  3. 搜索框防抖(Debounce)
  4. 并发请求合并(Zip与CombineLatest)
  5. 缓存优先策略(Concat)
  6. 错误处理与降级(OnErrorReturn)
  7. 常见问题问答(FAQ)
  8. 总结与最佳实践

RxJava为何仍是异步编程利器?

尽管Kotlin协程崛起,但RxJava在复杂数据流变换、背压处理、操作符丰富度上依然不可替代,对于Android开发者而言,理解RxJava的核心思想(观察者模式+链式调用)能极大提升代码可读性,下面通过5个真实案例展示其威力。

RxJava案例


案例一:网络请求自动重试(RetryWhen)

场景:用户点击“加载”按钮,网络偶发超时,希望自动重试2次,且每次间隔1秒。

Observable<Response> apiCall = api.getData()
    .retryWhen(errors -> errors.zipWith(Observable.range(1, 3), (e, i) -> i)
        .flatMap(retryCount -> Observable.timer(1, TimeUnit.SECONDS)))
    .doOnSubscribe(d -> showLoading())
    .subscribe(response -> showData(), throwable -> showError());

解析zipWith计数,timer延迟,若3次仍失败则走onError,此案例避免多层嵌套回调,且重试逻辑即时可见。


案例二:搜索框防抖(Debounce)

场景:用户输入关键词实时搜索,避免每次按键都请求服务器。

EditText input = findViewById(R.id.search_input);
RxTextView.textChanges(input)
    .debounce(400, TimeUnit.MILLISECONDS)
    .filter(text -> text.length() > 2)
    .switchMap(query -> api.search(query))
    .subscribe(results -> updateList(results));

关键点

  • debounce:停止输入400ms后才发射。
  • switchMap:若新输入到来,取消前一个搜索请求,确保只展示最新结果。

效果:极大减少无效请求,提升服务器负载能力。


案例三:并发请求合并(Zip与CombineLatest)

场景:首页需要同时获取用户信息+推荐列表,两者都成功后才展示UI。

Observable<User> userObs = api.getUser();
Observable<List<Item>> itemsObs = api.getRecommendations();
Observable.zip(userObs, itemsObs, (user, items) -> new HomeData(user, items))
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(data -> render(data));

对比CombineLatest用于其中任一数据变化则重新组合(如筛选条件+列表数据)。zip严格等待所有数据就绪。

注意:若请求之间存在依赖(B依赖A的结果),应使用flatMap链式调用。


案例四:缓存优先策略(Concat)

场景:优先展示本地缓存,再请求网络更新。

Observable<Data> cache = db.getCache().onErrorReturn(throwable -> null);
Observable<Data> network = api.getFreshData().doOnNext(data -> db.save(data));
Observable.concat(cache, network)
    .firstElement() // 只取第一个有效值
    .subscribe(data -> render(data));

优化:若缓存为空,concat会继续订阅network,配合firstElement避免页面闪烁。


案例五:错误处理与降级(OnErrorReturn)

场景:视频详情页加载失败时,显示默认封面图并提示重试。

api.getVideoDetail(id)
    .map(video -> video.getPlayUrl())
    .onErrorReturn(throwable -> DEFAULT_PLAY_URL)
    .subscribe(url -> player.play(url), throwable -> showError());

进阶onErrorResumeNext可返回新的Observable(如从备用服务器获取)。retry(2)可限制重试次数。


常见问题问答(FAQ)

Q1:RxJava与协程如何选择? A:团队已是协程风格则选协程;但若遇到复杂事件流(如用户操作+网络状态组合),RxJava操作符更直接,混合使用也很常见(如协程内部用asObservable())。

Q2:如何避免RxJava内存泄漏?
A:使用CompositeDisposableonDestroydispose();或者使用AutoDispose库绑定生命周期。

Q3:背压(Backpressure)是什么?何时需要处理?
A:上游发射速度 > 下游处理速度,当数据量过大(如传感器流)时,使用onBackpressureBufferonBackpressureDrop,网络请求一般不会遇到,但数据库大量导出时需注意。

Q4:和LiveData的区别?
A:LiveData负责感知生命周期但无变换能力;RxJava可做复杂变换但需手动管理生命周期,常用搭配:RxJava计算,LiveData观察结果。

Q5:调试有什么技巧?
A:用doOnNext/doOnError打印日志;或使用RxJava 3.x的RxJavaPlugins.setErrorHandler全局捕获异常。


总结与实用建议

  • 避免过度设计:简单功能用AsyncTask或回调即可,不要强行上RxJava。
  • 命名规范:操作符链按“每一步做一件事”拆分,用换行缩进增加可读性。
  • 线程调度:默认在哪个线程订阅就在哪个线程执行subscribe;联网用subscribeOn(Schedulers.io()),UI更新用observeOn(AndroidSchedulers.mainThread())
  • 测试辅助:用TestScheduler虚拟时间控制发射,便于单元测试。

5个案例覆盖了重试、防抖、合并、缓存、降级五种高频业务需求,如果你能透彻理解并灵活组合,处理日常App开发中的异步问题将游刃有余,希望本文的代码片段能成为你手边随时翻阅的参考手册。


如果你觉得有用,欢迎分享给团队技术同伴,或者在实际项目中替换为Kotlin版等价写法(如Flow),思路完全一致。

抱歉,评论功能暂时关闭!