Upload file in Android Java with retrofit 2

Vo Thanh Tung
4 min readNov 13, 2019

In this article, we will implement a function upload file with Retrofit2 for android. Retrofit2 is one of the most popular network request libraries for android.

1. Add retrofit 2 to gradle file (app level).

// retrofit, network request
implementation 'com.squareup.retrofit2:retrofit:2.6.1'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'

We also add Gson package which is used to parse JSON to Object when we get JSON return from API and of course we can convert a java object to JSON when we send post to the server.

2. Create Retrofit Instance


public class RetrofitClientInstance {

private static Retrofit retrofit;
private static final String BASE_URL_API = BuildConfig.WEB_URL_API;

public static Retrofit getRetrofitInstance() {
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60,TimeUnit.SECONDS).build();

if (retrofit == null) {
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(BASE_URL_API).client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}

As you can see we just declare one base API endpoint at the top of the class.

private static final String BASE_URL_API = BuildConfig.WEB_URL_API;

in this case, I get value from the grade file config, but you can change with your API endpoint. Then we create a retrofit instance, I also added a connection timeout is 60 s because the default of Retrofit time out is 10 second so when you upload a large size, time out can occur.

OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60,TimeUnit.SECONDS).build();

3. Create an interface to upload file

In this code, we will define a request which is needed to map with API, what type if request POST, GET or PUT. What is the parameter and API endpoint...

public interface UploadReceiptService {
@Multipart
@POST("/api/receipt/upload")
Call <List<UploadResult>>uploadReceipt(
@Header("Cookie") String sessionIdAndRz,
@Part MultipartBody.Part file,
@Part("items") RequestBody items,
@Part("isAny") RequestBody isAny
);
}

As you can see, we just declare these parameter

  1. API endpoint
https://baseUrl/api/receipt/upload 

Please make sure that you are using HTTPS if you are using HTTP Retrofit2 will throw the error.

2. HTTP Method

in this interface, we are using POST method to send a file to the server

3. Cookie

Luckily, Retrofit2 is supported to send a cookie to the server site. As you know almost API nowadays use token to validate user in some case, we can use a cookie. In my case, I have used cookies so I add cookies here.
You can create a cookie as String and just add to header.

@Header("Cookie") String sessionIdAndRz 

4. Post Parameters, upload the file and handle the response

This is the most important things, we need to send a file to the server. In this case, we are uploading files so we will `MultipartBody`

@Part MultipartBody.Part file,

And next is the body, you can send the body as JSON or text.

4. Upload the file

This is the way we create a request network from our main controller.

UploadReceiptService service = RetrofitClientInstance.getRetrofitInstance().create(UploadReceiptService.class);

String cookie = "cookiehere"
String stringValue = "stringValue"
file = new File(mFileName);

RequestBody requestFile =
RequestBody.create(
MediaType.parse("image/jpg"),
file
);

String items = "[1,2,4]";

MultipartBody.Part body =
MultipartBody.Part.createFormData("files[0]", file.getName(), requestFile);

RequestBody items = RequestBody.create(MediaType.parse("application/json"), items);
RequestBody stringValue = RequestBody.create(MediaType.parse("text/plain"), stringValue);

Call<List<UploadResult>> call = service.uploadReceipt(cookie, body, items, stringValue);

call.enqueue(new Callback<List<UploadResult>>() {
@Override
public void onResponse(Call<List<UploadResult>> call, Response<List<UploadResult>> response) {
if (response.code() == 204){
returnToTwa(response.body());
} else {

Toast.makeText(ResultDetectReceiptActivity.this, "Upload Error: " + response.message(), Toast.LENGTH_SHORT).show();
}

}

@Override
public void onFailure(Call<List<UploadResult>> call, Throwable t) {
Toast.makeText(ResultDetectReceiptActivity.this, "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
}
});

As the top line, we just initiated service with a retrofit client

UploadReceiptService service = RetrofitClientInstance.getRetrofitInstance().create(UploadReceiptService.class);

Next, creating parameters and pass these values to interface

Call<List<UploadResult>> call = service.uploadReceipt(cookie, body, items, stringValue);

Finally, catch the callback response from the server, in this callback. If return success we will handle at the function `onResponse` else failed we will handle at `onFailure`

call.enqueue(new Callback<List<UploadResult>>() {
@Override
public void onResponse(Call<List<UploadResult>> call, Response<List<UploadResult>> response) {
if (response.code() == 204){
// doing some thing here, like pare json to object, save to db ..
} else {

Toast.makeText(ResultDetectReceiptActivity.this, "Upload Error: " + response.message(), Toast.LENGTH_SHORT).show();
}

}

@Override
public void onFailure(Call<List<UploadResult>> call, Throwable t) {
Toast.makeText(ResultDetectReceiptActivity.this, "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
}
});

Bonus:

  1. Add debug

It is very important for debugging some cases when we must to know what is the api response. In some cases, the response can be not a json format instead of it is an HTML page, how we know what is the response? Fortunately, we can use the library interceptor

add interceptor to gradle app file, I got some issue when building the project, maybe you need to clean project and rebuild again.

implementation("com.squareup.okhttp3:logging-interceptor:4.7.2")

Add log to Retrofit client

if (DEBUG){
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(logging)
.connectTimeout(300, TimeUnit.SECONDS)
.readTimeout(300, TimeUnit.SECONDS).build();

}

2. Show Dialog

we can use ‘ProgressDialog’ to let the user know that the upload is processing. In order to user ProgressDialog, just declare a process dialog before call API and dismiss it when finishing upload file

//befor call request 
mProgressDialog
= new ProgressDialog(this);
mProgressDialog.setMessage(this.getString(R.string.progress_message_sending));
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.setCancelable(false);
mProgressDialog.show();

Then just dismiss the dialog after done calling.

public void onResponse(Call<List<UploadResult>> call, Response<List<UploadResult>> response) {
if (response.code() == 204){
returnToTwa(response.body());
} else {
if (mProgressDialog != null) {
try {
mProgressDialog.dismiss();
} catch (Exception e) { }
}

Toast.makeText(ResultDetectReceiptActivity.this, "Upload Error: " + response.message(), Toast.LENGTH_SHORT).show();
}

}

--

--