You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();

关键逻辑说明

  1. 实体与文件的关联保留:通过在flatMap内部处理单个实体的所有文件,不会丢失实体和文件的归属关系,这比直接用flatMapIterable展开所有文件更可控。
  2. 空文件实体处理:专门判断实体没有文件的情况,直接标记为已上传,符合业务逻辑。
  3. 全量上传成功判断:用toList()收集所有文件的上传结果,通过noneMatch(Objects::isNull)判断是否所有文件都上传成功,只有全部成功才会执行实体更新。
  4. 线程优化:上传操作放在Schedulers.io()线程,比原来的computation更适合IO密集型任务。
  5. 错误处理:可选的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:25:59