It's time to kick off a brand-new Retrofit topic and mini series: call adapters. In this first introductory tutorial you'll learn what call adapters are and how you can utilize them in Retrofit.
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
Call Adapter Basics — What Are They?
Before we can dive into call adapters, we need to go into the details of how Retrofit works. Retrofit uses an HTTP client (OkHttp) to execute the network requests. This execution happens on a background thread.
When OkHttp client receives a response from the server, it passes the response back to Retrofit. Retrofit then does its magic: it pushes the meaningless response bytes through converters and wraps it into a usable response with meaningful Java objects. This resource-intensive process is still done on a background thread. Finally, when everything is ready Retrofit needs to return the result to the UI thread of your Android app.
By default, this return wrapping is done as Call<TypedResponseClass>
type. This action of returning from the background thread, which receives and prepares the result, to the Android UI thread is a call adapter!
Basically, call adapters are sitting on top of Retrofit and offer the functionality to you as the developer. The call adapter of your choice decides how you interact with the Retrofit core. You've to understand that call adapters are in charge of controlling the management, execution and response handling of Retrofit. This might sound quite vague, but it'll become clear when you read on and see some examples.
Being able to change call adapters means you can completely change your app's Retrofit logic. Essentially, there are three approaches to call adapters:
- Keep the default
Call<TypedResponseClass>
call adapter - Integrate and use a pre-built call adapter that tie in Retrofit with an existing flow or logic framework
- Create a custom-build call adapter specifically implemented for your use case
Because we use the first option in the majority of our tutorials, we'll skip it in this introduction and focus on the latter two.
Integrate Pre-built Call Adapters
As mentioned above, there are pre-build call adapters. We differentiate between two kinds: first-party and third-party call adapters.
First-Party Call Adapters
The developers of Retrofit provide multiple call adapters for common frameworks. At the time of writing this tutorial it is RxJava, RxJava 2, Guava, Java 8. You can add them as a dependency via Gradle:
dependencies {
// Retrofit
compile 'com.squareup.retrofit2:retrofit:2.5.0'
// For example, add call adapter for RxJava 2
compile 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
// or alternatively:
compile 'com.squareup.retrofit2:adapter-rxjava:2.5.0'
compile 'com.squareup.retrofit2:adapter-guava:2.5.0'
compile 'com.squareup.retrofit2:adapter-java8:2.5.0'
}
Retrofit Instance
After syncing your project you can access the call adapter's code. However, this isn't enough. In order to let Retrofit know that it shouldn't wrap responses in the default Call<>
anymore and instead use, for example, RxJava 2's Observable<>
, you need to change your Retrofit declaration:
Retrofit retrofit =
new Retrofit.Builder()
.baseUrl(apiBaseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
In the snippet above we've added the addCallAdapterFactory(RxJavaCallAdapterFactory.create())
method call. Consequently, this Retrofit instance can now also wrap the responses in RxJava types. However, the preparation isn't completely done yet.
Interface Declaration
Of course, you'll also need to update your interface declaration. The return type of the method needs to be updated to reflect the new RxJava type:
public interface GistService {
// OLD standard call adapter type
@GET("gists")
Call<List<Gist>> getGists();
// NEW RxJava call adapter type
@GET("gists")
Observable<List<Gist>> getGists();
}
Multiple Call Adapters
It's important to note that you don't need to change your entire app over to one exclusive call adapter, because you can mix them! Use the call adapter that fits your method and scenario, even if it means you use two (or more!) different call adapters within your app. This is explicitly supported:
public interface GistService {
// access Gists with default call adapter
@GET("gists")
Call<List<Gist>> getGists();
// create new Gist with RxJava call adapter
@POST("gists")
Observable<ResponseBody> createGist(@Body Gist gist);
}
Even with this mixed declaration you can use the single Retrofit instance from above. If you need even more call adapters, you can also add them to the Retrofit instance with another addCallAdapterFactory()
call. Similar to Retrofit's converter management, Retrofit will manage all of them and pick the call adapter that fits the method.
This would be all you need to set up your app for the RxJava call adapter. Of course, we only showed you one out of the four first-party call adapters, but the others principally work the same. We'll take a closer look at each of them in dedicated future tutorials.
Call adapters are not just limited to these four, you should be aware that there are other call adapters as well.
Third-Party Adapters
Of course, you can always write an call adapter for your logic framework, if you don't use RxJava or one of the others. At the time of writing, call adapters for Bolts and Agera are published and supported by third-party developers.
Custom Adapters
Finally, and for us the most interesting call adapters: custom ones. Call adapters can be powerful and clean solutions to messy problems. You'll learn how to implement your custom call adapters in upcoming tutorials. A variety of sample usages will demonstrate how efficient call adapters can be. For example, Retrofit's two default callbacks (onResponse
and onFailure
) are not very convenient. In the next tutorials you'll learn to setup your own callback mechanism!
Summary
In this tutorial you've seen an introduction into Retrofit call adapters. You've learned what their purpose is and how you can add one of the first-party call adapters. You are now also aware that there are third-party and custom call adapters as well. Of course, this was only the beginning and we'll start with the fun stuff in the next tutorial.
Do you have further questions on this topic or about Retrofit in general? Just let us know on Twitter @futurestud_io or leave a comment below.
Enjoy coding & make it rock!