RxJava+Retrofit多图上传:串行执行与批量成功回调需求咨询
Alright, let's tackle these two image upload scenarios step by step using your existing single-image upload API as the foundation. First, let's recap the API and response model we're working with:
Single-Image Upload API
@Multipart @POST("addImage") Observable<ImageUploadResponse> savePhoto(@Part MultipartBody.Part image);
Server Response POJO
Make sure you have this model class set up (using Gson/Moshi for parsing):
public class ImageUploadResponse { private boolean isSuccess; private boolean isError; private String message; private PayLoad payLoad; // Getters, setters, and inner PayLoad class public static class PayLoad { private String imagePath; // Getters and setters } }
Scenario 1: Parallel Uploads - Trigger onNext Only When All Succeed
Approach
We want to upload all images at the same time, and only emit a result if every upload is successful. Here's how to pull it off:
- Convert your list of image parts into an Observable stream.
- Use
flatMapto kick off each single-image upload in parallel. - Validate each response—if any upload fails, throw an error to stop the sequence.
- Use
toList()to wait for all successful uploads, then emit the collected results.
Code Implementation
// Assume you've already converted your images to MultipartBody.Part List<MultipartBody.Part> imageParts = ...; Observable.fromIterable(imageParts) .flatMap(imagePart -> apiService.savePhoto(imagePart) // Validate each upload response .map(response -> { if (!response.isSuccess()) { throw new RuntimeException("Upload failed: " + response.getMessage()); } return response.getPayLoad().getImagePath(); }) // Optional: Add retry logic for transient failures .retry(2)) // Wait for all uploads to succeed, then collect paths into a list .toList() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( successfulImagePaths -> { // All images uploaded successfully! // Run your onNext logic here with the list of paths }, error -> { // At least one upload failed—handle the error here } );
Key Notes
toList()is perfect here: it waits for every upstream emission to complete, then emits a single list. If any upload fails, the sequence jumps straight toonError.- We added a
mapoperator to validate each response—this ensures only successful uploads contribute to the final result. subscribeOn(Schedulers.io())keeps network calls off the UI thread, whileobserveOn(AndroidSchedulers.mainThread())brings the result back to your app's UI layer (adjust if you're not building for Android).
Scenario 2: Serial Uploads - Get ArrayList of Results When All Succeed
Approach
For sequential uploads (one after another), we'll swap flatMap with concatMap—this operator processes each upload in order, waiting for the previous one to finish before starting the next. Then we'll collect all successful results into an ArrayList as requested.
Code Implementation
List<MultipartBody.Part> imageParts = ...; Observable.fromIterable(imageParts) // Use concatMap for strict sequential execution .concatMap(imagePart -> apiService.savePhoto(imagePart) .map(response -> { if (!response.isSuccess()) { throw new RuntimeException("Upload failed: " + response.getMessage()); } return response.getPayLoad().getImagePath(); }) .retry(2)) // Collect all paths into a list, then convert to ArrayList .toList() .map(ArrayList::new) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( arrayListOfPaths -> { // All images uploaded sequentially! // Use the ArrayList<String> of successful paths here }, error -> { // Any upload failed—handle the error here } );
Key Notes
concatMapguarantees sequential execution: each upload starts only after the previous one completes successfully. If any upload fails, the sequence stops immediately.map(ArrayList::new)converts the defaultListfromtoList()into anArrayListto match your requirement.- Just like the parallel scenario, we validate each response to ensure only successful uploads make it to the final list.
内容的提问来源于stack exchange,提问作者Surinder Singh

