Retrofit 2 — Reuse and Analyze Requests

Retrofit 2 fundamentally changes the way requests are made. Especially for developers, who are used to Retrofit 1.9 or earlier versions, the new Call class is something that takes time to get an understanding for. In this blog post, we'll show you some basic usage and features of this new mysterious class!

Before you learn more about the Call class, you might want to check out all the other Retrofit topics:

Retrofit Series Overview

  1. Introduction to Call Adapters (Coming soon)
  2. Custom Call Adapter to Separate OnResponse Callback (Coming soon)
  3. How to Integrate RxJava 1.x Call Adapter (Coming soon)
  4. How to Integrate RxJava 2.x Call Adapter (Coming soon)
  5. How to Integrate Guava Call Adapter (Coming soon)
  6. Custom Call Adapter to Separate Network and Gson Errors (Coming soon)
  1. Callbacks (Coming soon)
  2. Annotations (Coming soon)
  3. Fluent Interface with Builders (Coming soon)

Reuse of Call Objects

In this blog post, we'll make use of the code from our how to download files blog post. If you're interested in the details, give it a quick read. Otherwise, keep going. What kind of request it is, doesn't really matter. All the features we'll show you apply for all Retrofit requests.

One Request for Each Call Object

One of the first things you've to know about the Call class and its instances: each instance is special made for one and only one request. You cannot simply use the same object and call execute() or enqueue() again:

FileDownloadService downloadService = ServiceGenerator.create(FileDownloadService.class);

Call<ResponseBody> originalCall = downloadService.downloadFileWithDynamicUrlSync(fileUrl);  
Callback<ResponseBody> downloadCallback = new Callback<ResponseBody>() {...};

// correct usage:
originalCall.enqueue(downloadCallback);

// some other actions in between
// ...

// incorrect reuse:
// if you need to make the same request again, don't use the same originalCall again!
// it'll crash the app with a java.lang.IllegalStateException: Already executed.
originalCall.enqueue(downloadCallback); // <-- would crash the app  

Duplicated Call Objects

Instead, if you want to make the exact same request again, you can use the clone() method on the Call instance to create a copy of it. It'll contain the exact same settings and configuration. You can use the new copy to make an identical request to the server:

FileDownloadService downloadService =  
    ServiceGenerator.create(FileDownloadService.class);

Call<ResponseBody> originalCall =  
    downloadService.downloadFileWithDynamicUrlSync(fileUrl);
Callback<ResponseBody> downloadCallback = new Callback<ResponseBody>() {...};

// correct reuse:
Call<ResponseBody> newCall = originalCall.clone();  
newCall.enqueue(downloadCallback);  

This can be very useful if you need to send the same request multiple times.

Analyzing Requests With the Call Object

As you've already seen, Retrofit 2 includes the Call instance to every callback method. Thus, if the request was successful or even if it failed, you still can access the original Call object. But the reason to include it is not so that you can reuse the call (hint: use clone()), it's that you can analyze the request that was made using call.request(). This will return the complete request data. Let's look at an example:

FileDownloadService downloadService =  
    ServiceGenerator.create(FileDownloadService.class);

Call<ResponseBody> originalCall =  
    downloadService.downloadFileWithDynamicUrlSync(fileUrl);

originalCall.enqueue(new Callback<ResponseBody>() {  
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        checkRequestContent(call.request());
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        checkRequestContent(call.request());
    }
});

Both callback methods are passing the request to a new helper method checkRequestContent(), which accesses the request headers, body and url:

private void checkRequestContent(Request request) {  
    Headers requestHeaders = request.headers();
    RequestBody requestBody = request.body();
    HttpUrl requestUrl = request.url();

    // todo make decision depending on request content
}

This might be useful to you if you want to review the request, which was send to the server.

Preview Requests

It's also good to know that you can utilize call.request() at any time, even if the request wasn't scheduled or made yet! It'll generate the request just like it would for a regular network call.

Important: the call.request() method does some significant computing, if the request wasn't executed yet. It's not recommended to get a preview of the data via .request() on Android's UI/Main thread!

Summary

In this blog post, we've made you a little more familiar with the Call class and how to use it. We've shown that you can use each instance only once. Furthermore, we've also shown you a way how to duplicate requests. Finally, you've learned how you can analyze the request content at any time!

Do you have a firm grasp of the Call class yet? Let us know in the comments!

Explore the Library

Find interesting tutorials and solutions for your problems.

Miscellaneous