Retrofit 2 — How to Upload Multiple Files to Server

We've already shown you in a tutorial how to upload files to a server. In this tutorial, we'll show you a special case: uploading multiple files with one request.

If you want to catch up with one of our plenty Retrofit topics, check our outline of posts:

Retrofit Series Overview

  1. Introduction to Call Adapters (Coming soon)
  1. Callbacks (Coming soon)
  2. Annotations (Coming soon)
  3. Fluent Interface with Builders (Coming soon)

Upload Multiple Files With Retrofit 2

Before going into the details of uploading multiple files, please make sure you understand the principles of uploading files with Retrofit 2. The approach for multiple files is going to be very similar.

First of all, we need to extend our FileUploadService class for the new upload with multiple files:

public interface FileUploadService {  
    // previous code for single file uploads
    @Multipart
    @POST("upload")
    Call<ResponseBody> uploadFile(
            @Part("description") RequestBody description,
            @Part MultipartBody.Part file);

    // new code for multiple files
    @Multipart
    @POST("upload")
    Call<ResponseBody> uploadMultipleFiles(
            @Part("description") RequestBody description,
            @Part MultipartBody.Part file1,
            @Part MultipartBody.Part file2);
}

If you compare the two interface methods for uploadFile() and uploadMultipleFiles(), you can spot the difference very easily. Retrofit 2 makes it simple to add new file parts. On the side of the interface declaration, we just need to add another line @Part MultipartBody.Part file. The uploadMultipleFiles() method currently only supports exactly two files. You need to adjust the amount of MultipartBody.Part parts to your needs. In a later tutorial we'll look at a way to add a dynamic amount of files to your request.

Declaring the interface is only half of the work. The other part is the implementation in the activity or fragment lifecycle. Since we're working with multiple files now, we've implemented two helper methods to make things more robust:

@NonNull
private RequestBody createPartFromString(String descriptionString) {  
    return RequestBody.create(
            okhttp3.MultipartBody.FORM, descriptionString);
}

@NonNull
private MultipartBody.Part prepareFilePart(String partName, Uri fileUri) {  
    // https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java
    // use the FileUtils to get the actual file by uri
    File file = FileUtils.getFile(this, fileUri);

    // create RequestBody instance from file
    RequestBody requestFile =
        RequestBody.create(
            MediaType.parse(getContentResolver().getType(fileUri)), 
            file
        );

    // MultipartBody.Part is used to send also the actual file name
    return MultipartBody.Part.createFormData(partName, file.getName(), requestFile);
} 

The createPartFromString() method can be useful for sending descriptions along a multipart upload. The prepareFilePart() method builds a MultipartBody.Part object, which contains a file (like a photo or video). The wrapping in a MultipartBody.Part is necessary to upload files with Retrofit 2.

So let's use our helper methods to send two files:

Uri file1Uri = ... // get it from a file chooser or a camera intent  
Uri file2Uri = ... // get it from a file chooser or a camera intent

// create upload service client
FileUploadService service =  
        ServiceGenerator.createService(FileUploadService.class);

// create part for file (photo, video, ...)
MultipartBody.Part body1 = prepareFilePart("video", file1Uri);  
MultipartBody.Part body2 = prepareFilePart("thumbnail", file2Uri);

// add another part within the multipart request
RequestBody description = createPartFromString("hello, this is description speaking");

// finally, execute the request
Call<ResponseBody> call = service.uploadMultipleFiles(description, body1, body2);  
call.enqueue(new Callback<ResponseBody>() {  
    @Override
    public void onResponse(Call<ResponseBody> call,
            Response<ResponseBody> response) {
        Log.v("Upload", "success");
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.e("Upload error:", t.getMessage());
    }
});

That's all you need to do to send multiple files in one request. Of course, you could add another or many more parts to the interface, if necessary. Using this approach you can send as many files as you wish.

Summary

In this tutorial, you've learned how to upload multiple files. Additionally, we've shown you two helper methods to make file handling easier for you. Retrofit 2 assists you by simplifying the process. If you run into any problems, let us know in the comments!


Explore the Library

Find interesting tutorials and solutions for your problems.

Miscellaneous