RxAndroid多文件上传优化:移除whenAll辅助方法实现实体更新
解决方案:移除whenAll并实现实体批量上传后的正确更新
嘿,我明白你的需求啦——要去掉那个whenAll辅助方法,同时确保只有当某个实体的所有文件都上传成功后,才标记它为已上传并存储回数据库,最后所有实体处理完调用onComplete()。
先说说你原来代码的问题:之前的逻辑是每个文件上传完成就更新实体,这会导致同一个实体被多次更新,而且哪怕只有一个文件上传成功就标记,完全不符合“所有文件都成功才更新”的要求。现在我们用RxJava的操作符来优雅解决这个问题:
完整实现代码
Observable.fromIterable(entities) .flatMap(entity -> { List<File> files = entity.getFiles(); // 情况1:实体没有附属文件,直接标记为已上传并存储 if (files.isEmpty()) { return Observable.just(entity) .doOnNext(e -> { e.setUploaded(true); repository.store(e); }); } // 情况2:实体有文件,等待所有文件上传成功后再处理实体 return Observable.fromIterable(files) // 上传单个文件,指定IO线程处理(上传是IO操作,别用computation线程) .flatMap(file -> uploadImage(file) .subscribeOn(Schedulers.io()) // 可选:处理单个文件上传失败的情况,避免整个实体的处理中断 .onErrorReturn(error -> { Log.e("Upload", "Failed to upload file: " + file.getName(), error); return null; }) ) // 收集所有上传结果,判断是否全部成功 .toList() .map(uploadResults -> uploadResults.stream().noneMatch(Objects::isNull)) // 只有全部上传成功才继续执行实体更新 .filter(allSuccess -> allSuccess) // 触发实体更新逻辑 .flatMap(allSuccess -> Observable.just(entity)) .doOnNext(e -> { e.setUploaded(true); repository.store(e); }); }) // 忽略所有实体的处理结果,只等待全部实体处理完成 .ignoreElements() // 所有任务完成后调用onComplete() .doOnComplete(() -> onComplete()) // 别忘了订阅(如果之前没做的话) .subscribe();
关键逻辑说明
- 实体与文件的关联保留:通过在
flatMap内部处理单个实体的所有文件,不会丢失实体和文件的归属关系,这比直接用flatMapIterable展开所有文件更可控。 - 空文件实体处理:专门判断实体没有文件的情况,直接标记为已上传,符合业务逻辑。
- 全量上传成功判断:用
toList()收集所有文件的上传结果,通过noneMatch(Objects::isNull)判断是否所有文件都上传成功,只有全部成功才会执行实体更新。 - 线程优化:上传操作放在
Schedulers.io()线程,比原来的computation更适合IO密集型任务。 - 错误处理:可选的
onErrorReturn能捕获单个文件上传失败的情况,不会导致整个流中断,同时可以记录错误日志。
简化版(如果不需要处理单个文件失败)
如果你的业务要求只要有一个文件上传失败,就放弃该实体的更新,不需要单独处理错误,可以简化成这样:
Observable.fromIterable(entities) .flatMap(entity -> { List<File> files = entity.getFiles(); if (files.isEmpty()) { return Observable.just(entity) .doOnNext(e -> { e.setUploaded(true); repository.store(e); }); } // 等待所有文件上传完成(只要有一个失败,整个实体的流就会报错) return Observable.merge(files.stream() .map(file -> uploadImage(file).subscribeOn(Schedulers.io())) .collect(Collectors.toList())) .ignoreElements() .andThen(Observable.just(entity)) .doOnNext(e -> { e.setUploaded(true); repository.store(e); }); }) .ignoreElements() .doOnComplete(() -> onComplete()) .subscribe();
这样写既去掉了whenAll方法,又完美实现了你的业务需求~
内容的提问来源于stack exchange,提问作者devz
相关产品推荐
相关产品推荐

