This is the second post taking a closer look at the new Retrofit 2 Call
class. If you haven't read the first part, where we look on how to reuse and analyze the request using the Call
class, check it out here.
In this blog post, we'll show you how to cancel requests and how to test if a request failed or was cancelled. Both can be very useful for app developers, who need to interact with APIs. If you're interested, keep reading!
Of course, we've a whole library of other Retrofit posts for you:
Retrofit Series Overview
- Getting Started and Creating an Android Client
- Basics of API Description
- Creating a Sustainable Android Client
- URL Handling, Resolution and Parsing
- How to Change API Base Url at Runtime
- Multiple Server Environments (Develop, Staging, Production)
- Share OkHttp Client and Converters between Retrofit Instances
- Upgrade Guide from 1.9
- Beyond Android: Retrofit for Java Projects
- How to use OkHttp 3 with Retrofit 1
- Synchronous and Asynchronous Requests
- Send Objects in Request Body
- Add Custom Request Header
- Manage Request Headers in OkHttp Interceptor
- Dynamic Request Headers with @HeaderMap
- Multiple Query Parameters of Same Name
- Optional Query Parameters
- Send Data Form-Urlencoded
- Send Data Form-Urlencoded Using FieldMap
- How to Add Query Parameters to Every Request
- Add Multiple Query Parameter With QueryMap
- How to Use Dynamic Urls for Requests
- Constant, Default and Logic Values for POST and PUT Requests
- Cancel Requests
- Reuse and Analyze Requests
- Optional Path Parameters
- How to Send Plain Text Request Body
- Customize Network Timeouts
- How to Trust Unsafe SSL certificates (Self-signed, Expired)
- Dynamic Endpoint-Dependent Interceptor Actions
- How to Update Objects on the Server (PUT vs. PATCH)
- How to Delete Objects on the Server
- Introduction to (Multiple) Converters
- Adding & Customizing the Gson Converter
- Implementing Custom Converters
- How to Integrate XML Converter
- Access Mapped Objects and Raw Response Payload
- Supporting JSON and XML Responses Concurrently
- Handling of Empty Server Responses with Custom Converter
- Send JSON Requests and Receive XML Responses (or vice versa)
- Unwrapping Envelope Responses with Custom Converter
- Wrapping Requests in Envelope with Custom Converter
- Define a Custom Response Converter
Cancel Requests
Let's use our example code from the how to download files with Retrofit blog post. But the exact request doesn't matter, since this is applicable to any Retrofit request. We've added a new activity, which creates a new request and executes it just like we usually do:
public class CallExampleActivity extends AppCompatActivity {
public static final String TAG = "CallInstances";
private Callback<ResponseBody> downloadCallback;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file_download);
FileDownloadService downloadService =
ServiceGenerator.create(FileDownloadService.class);
String fileUrl = "http://futurestud.io/test.mp4";
Call<ResponseBody> call =
downloadService.downloadFileWithDynamicUrlSync(fileUrl);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.d(TAG, "request success");
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e(TAG, "request failed");
}
};);
}
// other methods
// ...
}
Now let's assume the user clicked the "Abort" button or the app moved into a state where the request isn't necessary anymore: we need to cancel the request. In Retrofit 2, this can easily be done by using call.cancel();
. This will either cancel the network request, if it's not already running, or not start the request at all. That's it! If we expand the relevant request code by a simple cancel action, it'd look like this:
String fileUrl = "http://futurestud.io/test.mp4";
Call<ResponseBody> call =
downloadService.downloadFileWithDynamicUrlSync(fileUrl);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.d(TAG, "request success");
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e(TAG, "request failed");
}
});
}
// something happened, for example: user clicked cancel button
call.cancel();
}
Check If Request Was Cancelled
If you cancel the request, Retrofit will classify this as a failed request and thus call the onFailure()
callback in your request declaration. This callback is also used when there is no Internet connection or something went wrong on the network level. From the app perspective, these errors are quite a bit different. Thus, it's pretty helpful to know if a request was cancelled or if the device has no Internet connection.
Fortunately, the Call
class offers a isCanceled()
method to check whether the request was cancelled or not. With this little check you can distinguish various errors in your callback:
new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.d(TAG, "request success");
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
if (call.isCanceled()) {
Log.e(TAG, "request was cancelled");
}
else {
Log.e(TAG, "other larger issue, i.e. no network connection?");
}
}
};
Summary
And that's it! Retrofit 2 makes it really easy to cancel requests and also check if a request was cancelled. It can be a very handy tool in your Retrofit toolset.
If you've any questions, let us know in the comments!