如何用RxJava+Retrofit优雅实现拉取List<A>后遍历请求对应List<B>合并返回

需求说明
- 第一步:通过参数tab1调用远端服务器API1查询Head列表
- 第二步:遍历Head列表,针对每个Head通过API2查询对应的body列表,将Head与对应列表合并
- 最终输出
List<Wrapper<Head, List>>类型数据用于UI渲染
优化实现方案
这个场景属于典型的「嵌套请求+结果聚合」业务场景,通过RxJava操作符组合可以直接整合成单一流处理,不需要拆分两个独立请求逻辑,也不需要手动维护请求完成计数、中间LiveData中转:
// 单方法完成全流程请求,不需要拆分多步逻辑 public void queryFullListData(LifecycleOwner lifecycleOwner, MaterialZone mz, int pageNum) { VersaApiService.INSTANCE.getService(MaterialService.class) // 第一步:请求Header列表 .queryMaterialCategory("9223372036854775807", mVerticalPageNum, VERTICAL_PAGE_SIZE) .compose(RxUtil.applyScheduler(lifecycleOwner)) // 解析得到Header列表 .map(pageResult -> pageResult.getResult().getRecords()) // 将List<Header>拆分为单个Header逐个发射 .flatMapIterable(headers -> headers) // 对每个Header异步请求对应的Body列表,同时保留Header引用用于合并 .flatMap(header -> VersaApiService.INSTANCE.getService(MaterialService.class) .queryMaterial(header.getCategoryId(), mVerticalPageNum, VERTICAL_PAGE_SIZE) .compose(RxUtil.applyScheduler(lifecycleOwner)) // 解析Body列表,和对应Header合并为Wrapper对象 .map(bodyPageResult -> { List<Body> bodies = bodyPageResult.getResult().getRecords(); HeaderBodyWrapper wrapper = new HeaderBodyWrapper(); wrapper.setMaterialGroup(header); wrapper.setMaterials(bodies); return wrapper; }) // 可选降级逻辑:单个Body请求失败时返回空内容Wrapper,不阻断整个流程 .onErrorReturnItem(new HeaderBodyWrapper(header, Collections.emptyList())) ) // 所有请求完成后,将所有Wrapper聚合为最终列表 .toList() .subscribe(wrappers -> { // 直接拿到最终结果更新UI mGroups.setValue(wrappers); }, throwable -> { // 统一异常处理 VLog.d(HORIZONTAL_PAGE_SIZE + ", " + VERTICAL_PAGE_SIZE); VLog.d("onError: " + throwable.getMessage()); }); }
方案优势
- 逻辑简化:全流程在单个RxJava流中完成,不需要中间LiveData中转,也不需要手动判断所有请求是否完成,避免了原实现中单个请求失败就永远无法触发UI更新的问题
- 效率更高:flatMap默认支持并发请求多个Body接口,比循环串行请求效率更高;如果需要最终列表顺序和Header列表顺序一致,可将flatMap替换为
concatMapEager,在保持并发的同时保证输出顺序 - 通用性强:这套操作符组合可以直接复用在所有「先查列表、再查每个子项关联数据、最后聚合结果」的同类业务场景中
内容的提问来源于stack exchange,提问作者Maximillian
相关产品推荐
相关产品推荐

