Android中如何通过Retrofit的@PartMap传递指定格式的图片请求
Hey there! Let's work through this Retrofit multipart upload issue together. Since you're new to Retrofit and Android, I'll break this down clearly so you can follow along.
Your goal is to send a request with two files under the same image key plus a service_request string, formatted like:
{ "image": img1.jpg, "image": img2.jpg, "service_request": "asd123123asfsf" }
The problem with your current code is that you're using individual @Part parameters, and you want to know how to use @PartMap instead. But here's a quick heads-up: @PartMap uses a key-value structure where keys are unique, so we can't directly add two entries with the same image key. Instead, the most flexible way to handle duplicate field names (like your two image files) is to use MultipartBody.Builder to construct your request. Let's dive into the solution:
Step 1: Update Your Retrofit Service Interface
First, we'll simplify the interface. We don't need to manually set the Content-Type header—Retrofit automatically handles that for multipart requests. We'll switch to using a @Body parameter to accept the fully built multipart request:
import okhttp3.RequestBody; import okhttp3.ResponseBody; import retrofit2.Call; import retrofit2.http.Body; import retrofit2.http.Header; import retrofit2.http.POST; public interface YourApiInterface { @POST("http://192.168.1.100:8000/yrtp/service/request/upload") Call<ResponseBody> uploadImages( @Header("Authorization") String token, @Body RequestBody requestBody ); }
Step 2: Rewrite the uploadMultipleFiles() Method
Now we'll use MultipartBody.Builder to create a request that includes two image files and your service_request string. This builder lets us add multiple fields with the same name, which is exactly what you need:
private void uploadMultipleFiles() { // Get your stored values from SharedPreferences SharedPreferences preferences = getApplicationContext().getSharedPreferences("MY_APP", Context.MODE_PRIVATE); String retrievedToken = "Token " + preferences.getString("TOKEN", null); String attachmentOne = preferences.getString("Attachement_one", null); String attachmentTwo = preferences.getString("Attachement_two", null); String serviceRequestValue = "asd123123asfsf"; // Replace with your actual value, or pull from preferences // Create File objects for your images File fileOne = new File(attachmentOne); File fileTwo = new File(attachmentTwo); // Build the multipart request MultipartBody.Builder builder = new MultipartBody.Builder() .setType(MultipartBody.FORM); // Mark this as a multipart/form-data request // Add the first image file RequestBody fileBody1 = RequestBody.create(MediaType.parse("image/jpeg"), fileOne); // Use "image/png" if your file is a PNG builder.addFormDataPart("image", fileOne.getName(), fileBody1); // Add the second image file (same "image" key!) RequestBody fileBody2 = RequestBody.create(MediaType.parse("image/jpeg"), fileTwo); builder.addFormDataPart("image", fileTwo.getName(), fileBody2); // Add the service_request text field RequestBody serviceRequestBody = RequestBody.create(MediaType.parse("text/plain"), serviceRequestValue); builder.addFormDataPart("service_request", null, serviceRequestBody); // Finalize the request body RequestBody requestBody = builder.build(); // Execute the request Call<ResponseBody> call = ServiceBuilder.getInstance().getApi().uploadImages(retrievedToken, requestBody); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if (!response.isSuccessful()) { System.out.println("Upload failed! Response Code: " + response.code()); return; } System.out.println("Upload successful! Response Code: " + response.code()); } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { System.out.println("Upload error: " + t.getMessage()); } }); }
What About @PartMap?
As I mentioned earlier, @PartMap uses a unique key for each entry, so you can't add two image fields directly with it. That said, here's how you'd use @PartMap for cases where all your field keys are unique (for reference):
Service Interface for @PartMap
@Multipart @POST("http://192.168.1.100:8000/yrtp/service/request/upload") Call<ResponseBody> uploadWithPartMap( @Header("Authorization") String token, @PartMap Map<String, RequestBody> partMap );
Usage Example
Map<String, RequestBody> partMap = new HashMap<>(); // Add a single image (can't add a second with the same key) partMap.put("image\"; filename=\"" + fileOne.getName() + "\"", RequestBody.create(MediaType.parse("image/jpeg"), fileOne)); // Add service_request partMap.put("service_request", RequestBody.create(MediaType.parse("text/plain"), serviceRequestValue)); // Execute request Call<ResponseBody> call = ServiceBuilder.getInstance().getApi().uploadWithPartMap(retrievedToken, partMap);
But since you need two image fields, the MultipartBody.Builder approach is the right fit for your use case.
Quick Tips for Success
- Use the correct MediaType: Instead of
*/*, useimage/jpegorimage/pngfor images—this helps the backend correctly handle your files. - Check file paths: Make sure the paths stored in SharedPreferences are valid, or you'll get a
FileNotFoundException. - Handle permissions: On Android 6.0+, you need to request
READ_EXTERNAL_STORAGEpermission dynamically to access files from the device storage.
内容的提问来源于stack exchange,提问作者Sapthagiri Manivannan

