RxJava嵌套链式调用行为异常 无法将嵌套请求结果更新至目标对象
问题根因
你的代码中嵌套的图片下载Observable属于未被订阅的冷流,完全没有接入整个响应式链式结构:你在for循环内部创建了下载tile、拼接bitmap的流,但既没有将这个流返回给外层flatMap操作符,也没有将它的执行和当前tileLevels的发射逻辑做串联。RxJava中冷流只有在被下游订阅时才会执行,因此你写的doOnSuccess逻辑根本不会触发,tileLevel对象自然始终无法被更新。
修复方法
必须把预览图下载、Bitmap拼接的逻辑作为流的一部分串联到主链上,不能在操作符的lambda中创建孤立的流。核心调整点如下:
- 遍历tileLevels找到第一个符合预览条件的对象后,将下载拼接逻辑作为当前flatMap的返回流,保证订阅触发时逻辑会按顺序执行
- 等Bitmap拼接完成、tileLevel对象更新完毕后,再把完整的tileLevels列表发射给下游,供
combineLatest组装ArtObject使用 - 不要依赖doOnSuccess做核心业务状态更新,用map/flatMap等操作符把状态更新作为流执行的一部分,保证执行顺序可控
修复后对应代码段(替换原getImageTileLevels后的flatMap逻辑即可):
.flatMap((Function<List<ImageTileLevel>, ObservableSource<List<ImageTileLevel>>>) imageTileLevels -> { // 查找第一个符合预览要求的tileLevel int previewPos = -1; for (int i = 0; i < imageTileLevels.size(); i++) { if (imageTileLevels.get(i).suitsForPreview()) { previewPos = i; break; } } // 无符合条件的预览层级直接返回原列表 if (previewPos == -1) { return Observable.just(imageTileLevels); } ImageTileLevel targetLevel = imageTileLevels.get(previewPos); targetLevel.setPreview(true); // 下载、拼接逻辑接入主链,执行完成后再返回更新后的列表 return Observable.fromIterable(targetLevel.getTiles()) .concatMap(tile -> apiService.downloadFileWithDynamicUrlAsync(tile.getUrl()) .subscribeOn(Schedulers.io())) .toList() .map(responses -> { ArrayList<Bitmap> bitmaps = new ArrayList<>(); for (Response<ResponseBody> resp : responses) { if (resp.isSuccessful() && resp.body() != null) { bitmaps.add(BitmapFactory.decodeStream(resp.body().byteStream())); } } targetLevel.combineBitmaps(bitmaps); return imageTileLevels; }) .toObservable(); })
优化提示
- 你在
getArtObjectInfo和getImageTileLevels处重复声明了subscribeOn(Schedulers.io()),最外层已经指定IO调度器的前提下可以移除,简化代码 - Bitmap拼接属于CPU密集型操作,如果数据量较大,建议将拼接逻辑切换到
Schedulers.computation()调度器,避免阻塞IO线程 - 记得对ResponseBody做成功状态和空值判断,避免接口返回异常时触发空指针崩溃
内容的提问来源于stack exchange,提问作者Graworks
相关产品推荐
相关产品推荐

