Retrofit basics

Let’s have a look at a theoretical introduction to Retrofit before we move on to coding.

For a more complete and in-depth explanation, check out our complete Retrofit course

Converts a HTTP api into an interface

The main thing retrofit does is it converts an HTTP api into an interface that we can use in our programs. It converts communication over the web into a simple object that we can use in our code in an object oriented way to perform whatever communication we need. It takes care of everything and lets us simply invoke a function to retrieve information from the web. This is a huge advantage and the main purpose of Retrofit.

Facilitates network communication - both synchronous and asynchronous

It also allows for both synchronous and asynchronous communications. 

  • Synchronous means that when we send a request, we will wait for a reply before we do anything else.
  • Asynchronous means that we send a request, we continue on with out code and when the reply comes in, we have a function that is invoked and the reply is processed.

So that is the difference between the two cases, and Retrofit allows us to do both, depending on what we need for that particular program.

Importantly, on Android we are not allowed to perform synchronous network communication on the main thread. If that happens, the application will crash as soon as the method is invoked. So in order to do that, we have different ways on Android to pass a network call on a background thread.

<synchronous communication reference>

However we can absolutely perform asynchronous communications on the main thread because asynchronous communications simply calls a backend api and continues on with the processing until the response is returned.

Facilitates data conversion into objects

The message that is received from the backend, with the HTTP call, can be easily converted into an object that can be used in code. So not only is the network call converted into a function, but the response from that call is also transformed into an object that can be used in code.

Handles network retries, errors, caching etc

And of course Retrofit handles everything in the background so that we don’t really need to worry about it. So it handles network retries, errors, caching and a lot more. 

We can of course intercept some functionality, so for instance if we want to do some error handling, we can intercept all the errors and handle those, but the point is that Retrofit handles the network communication in a way that retrieves the errors and facilitates us using that functionality such as caching etc. 

So let’s have a look at the basics, how do you actually implement Retrofit in your code?

3 main components

In actuality we have 2 mandatory components, we will discuss them shortly, and one that is sort of optional, it’s more of a structure that I prefer to have in my projects. I use this in pretty much any project that I build and I do recommend that you use something similar at least to this structure.

POJO

So the first component is a POJO. That simply means a Plain Old Java Object, which is a class that is supposed to store some data, some information. The reason we need this class is because Retrofit uses this class to return us the information that it receives from the backend. 

So what we do in this class is basically we define the type of information that we want to have retrieved from the backend. This information has to correspond exactly to the information in the response that we get. Then Retrofit retrieves that information and parses it into our data class.

data class User {

    val userName: String,

    val firstName: String

}

In the small example here I have a data class User and I’m receiving two pieces of information, username and firstname. Retrofit parses the reply information, stores it in this class and gives it to us once it becomes available. So that is what the POJO class is for.

Interface

The second component is the interface. It tells Retrofit which endpoint we want to communicate with, and how.

interface UserApi{

    @GET(“getUser”)

    fun callGetUser(): Call<User>

}

In this example I have a get request to the endpoint called getUser. This is the endpoint where the API resides on the backend. So we have the function that we define, we can call this function anything we like, in the example it’s called callGetUser. Retrofit converts that network communication into a function that we can use in our project. So in this case, in order to actually perform the communication on the network, we simply need to call the callGetUser function.

This function will return an object of type Call, which is an internal Retrofit class, that will give us our POJO User. So you can see that the function we create here, which communicates with the backend API will return us User objects, which we provided the structure for above. 

The Call object is important because it allows us to perform the operation on the network in two different ways. Either synchronously or asynchronously, we will see later on what that means.

For the purposes of this example, we will be using asynchronous communication, because we don’t want to put that communication in a backend thread ourselves, we will let Retrofit do that for us. Retrofit provides that functionality, it will do the call on a background thread so we don’t need to worry about that in our project. 

So you can see the two main component of Retrofit, one is the function that we invoke in order to perform the network communication and then we have the data that we want to retrieve from that backend endpoint. 

Service

The third component that I like to create when working with Retrofit is the Service. The reason why we create this structure is because we will have an object which in Kotlin is basically a singleton. So this will provide a single point of access for our network communications. It will prevent us from instantiating our user API more than once, we will use the same API for all our communications.

object UserService {

    val BASE_URL=”https://mydomain.com/api/”

    val userApi = Retrofit.Builder()

        .baseUrl(BASE_URL)

        .addConverterFactory(…)

        .build()

        .create(UserApi::class.java)

}

So the UserService provides us with a BASE_URL. Then, the way we create our userApi is we have a Retrofit builder class that takes the base url and also a ConverterFactory.

The response from the backend can come in different formats. One of the most common ones is a JSON format. In order for Retrofit to know which type of data comes back and which converter to use to convert that data into our class, we need to provide the right type of converter factory. There are a few standard converters such as

GsonConverterFactory.create()

Then the final step is we build our service and we create it based on the api that we provide, in this case we use the interface that we defined earlier.

So what this will do is it will give us an object UserService that has a variable userApi that we can use to perform our calls and retrieve the information from the backend.

For a more complete and in-depth explanation, check out our complete Retrofit course

Close Bitnami banner
Bitnami