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

如何批量发起Retrofit2 Call并统一回调?多图上传如何改为单次请求?

嘿,我来帮你搞定这两个Retrofit2的实战问题,都是日常开发里很常见的场景:

问题1:如何发起多个Retrofit2 Call请求,所有请求完成后执行统一回调

这里有几种靠谱的实现方式,按推荐程度排序:

方式1:用RxJava(最简洁推荐)

Retrofit支持RxJava适配器,借助Rx的操作符可以轻松实现批量请求的统一回调。比如用Single.zip(需要获取每个请求的结果)或者Completable.mergeArray(只需要确认所有请求完成,不需要结果)。

步骤:

  1. 先添加RxJava相关依赖(确保你的Retrofit版本适配):
implementation 'io.reactivex.rxjava3:rxjava:3.1.5'
implementation 'io.reactivex.rxjava3:rxandroid:3.0.2'
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
  1. 修改Retrofit接口,让方法返回Single/Observable而不是Call:
public interface ApiService {
    @GET("data1")
    Single<DataModel1> fetchData1();

    @GET("data2")
    Single<DataModel2> fetchData2();
}
  1. 创建Retrofit实例时添加RxJava适配器:
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://your-api-url.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
        .build();

ApiService apiService = retrofit.create(ApiService.class);
  1. 合并多个请求并统一处理:
// 如果需要获取每个请求的结果,用Single.zip
Single.zip(
        apiService.fetchData1(),
        apiService.fetchData2(),
        (data1, data2) -> new CombinedResult(data1, data2) // 封装多请求结果
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
        combinedResult -> handleSuccess(combinedResult), // 所有请求成功完成
        throwable -> handleError(throwable) // 任意请求失败触发
);

// 如果只需要确认所有请求完成,不需要结果,用Completable.mergeArray
Completable.mergeArray(
        apiService.fetchData1().ignoreElement(),
        apiService.fetchData2().ignoreElement()
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
        this::handleAllComplete, // 全部完成回调
        this::handleError // 任意失败回调
);

方式2:用Java CompletableFuture(无Rx依赖)

如果不想引入RxJava,Java 8+的CompletableFuture也能实现:

步骤:

  1. 把Retrofit的Call转换成CompletableFuture:
private <T> CompletableFuture<T> callToFuture(Call<T> call) {
    CompletableFuture<T> future = new CompletableFuture<>();
    call.enqueue(new Callback<T>() {
        @Override
        public void onResponse(Call<T> call, Response<T> response) {
            if (response.isSuccessful()) {
                future.complete(response.body());
            } else {
                future.completeExceptionally(new IOException("Request failed: " + response.code()));
            }
        }

        @Override
        public void onFailure(Call<T> call, Throwable t) {
            future.completeExceptionally(t);
        }
    });
    return future;
}
  1. 批量执行并等待全部完成:
ApiService apiService = retrofit.create(ApiService.class);

CompletableFuture<DataModel1> future1 = callToFuture(apiService.fetchData1Call());
CompletableFuture<DataModel2> future2 = callToFuture(apiService.fetchData2Call());

// 等待所有任务完成
CompletableFuture.allOf(future1, future2)
        .thenApply(v -> new CombinedResult(future1.join(), future2.join()))
        .whenComplete((result, throwable) -> {
            if (throwable != null) {
                handleError(throwable);
            } else {
                handleSuccess(result);
            }
        });

方式3:手动管理计数器(不推荐,易出错)

如果以上两种都不想用,也可以手动维护一个计数器,每个请求完成后递增,达到总数时触发回调:

private int completedCount = 0;
private static final int TOTAL_REQUESTS = 2;
private CombinedResult combinedResult = new CombinedResult();

// 发起第一个请求
apiService.fetchData1Call().enqueue(new Callback<DataModel1>() {
    @Override
    public void onResponse(Call<DataModel1> call, Response<DataModel1> response) {
        if (response.isSuccessful()) combinedResult.setData1(response.body());
        checkIfAllCompleted();
    }

    @Override
    public void onFailure(Call<DataModel1> call, Throwable t) {
        handleError(t);
    }
});

// 发起第二个请求
apiService.fetchData2Call().enqueue(new Callback<DataModel2>() {
    @Override
    public void onResponse(Call<DataModel2> call, Response<DataModel2> response) {
        if (response.isSuccessful()) combinedResult.setData2(response.body());
        checkIfAllCompleted();
    }

    @Override
    public void onFailure(Call<DataModel2> call, Throwable t) {
        handleError(t);
    }
});

// 检查是否所有请求完成
private void checkIfAllCompleted() {
    completedCount++;
    if (completedCount == TOTAL_REQUESTS) {
        handleSuccess(combinedResult);
    }
}

这种方式代码冗余,且失败场景需要额外处理,尽量不用。


问题2:将多张图片独立上传改为单次请求批量上传

这个核心是利用Retrofit的**Multipart(多部分表单)**请求,一次请求里携带多个文件。

步骤:

  1. 修改Retrofit接口,定义支持多文件上传的Multipart请求:
public interface ApiService {
    // 方式2:动态数量的文件,用@PartMap(更灵活,推荐)
    @Multipart
    @POST("upload/multiple")
    Call<UploadResponse> uploadMultipleImages(@PartMap Map<String, MultipartBody.Part> images);
}
  1. 构建Multipart请求体,把所有图片转换成MultipartBody.Part:
// 假设你有一个图片文件列表List<File> imageFiles
Map<String, MultipartBody.Part> imagePartMap = new HashMap<>();

for (int i = 0; i < imageFiles.size(); i++) {
    File file = imageFiles.get(i);
    // 创建请求体
    RequestBody requestBody = RequestBody.create(file, MediaType.parse("image/jpeg"));
    // 构建MultipartBody.Part,参数对应服务器接收的字段名、文件名、请求体
    MultipartBody.Part imagePart = MultipartBody.Part.createFormData(
            "files", // 服务器端对应的字段名,比如Spring Boot用@RequestParam("files")
            file.getName(),
            requestBody
    );
    imagePartMap.put("file" + (i+1), imagePart);
}
  1. 发起单次请求并处理回调:
ApiService apiService = retrofit.create(ApiService.class);
Call<UploadResponse> call = apiService.uploadMultipleImages(imagePartMap);

call.enqueue(new Callback<UploadResponse>() {
    @Override
    public void onResponse(Call<UploadResponse> call, Response<UploadResponse> response) {
        if (response.isSuccessful()) {
            handleUploadSuccess(response.body());
        } else {
            handleUploadError(response.message());
        }
    }

    @Override
    public void onFailure(Call<UploadResponse> call, Throwable t) {
        handleUploadError(t.getMessage());
    }
});

注意事项:

  • 确保服务器端支持接收多个文件,比如Spring Boot后端可以这样写:
@PostMapping("/upload/multiple")
public ResponseEntity<UploadResponse> uploadMultipleFiles(@RequestParam("files") MultipartFile[] files) {
    // 处理多个文件逻辑
}
  • 注意配置客户端和服务器的文件大小阈值,避免因文件过大导致上传失败。

内容的提问来源于stack exchange,提问作者Riyas Ahamed

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:33:36