Retrofit Tutorial in Android – Part 1 Introduction

Retrofit tutorial in android

Last Updated on February 4, 2020 by Aram

Retrofit is the best library that lets you connect to HTTP-based API services from your Android App. It leverages the OkHttp library’s core functionality, adding a bunch of features to it while eliminating the boilerplate code that should be written in case you want to only implement the OkHttp library and have any of the features that Retrofit provides.

Retrofit offers several powerful features such as the ability to cancel the request in an easy way, specify the request headers such as passing Authorization header through the annotations or intercepting the request, applying various types of Converters to convert your request/response objects to your preferred formatting, and more.

Retrofit leverages the use of Callbacks, and a callback overrides 2 methods: onResponse() and onFailure()

In this tutorial, I’ll be using the GsonFactoryConverter for our Retrofit  implementation. Gson is a simple library that allows you to easily deal with  the request/response objects of the APIs and convert them to and from Json format. The GsonFactoryConverter will handle the conversion part on behalf of you, without you having to include the Gson library.

One of the great features of Retrofit, is that it converts your HTTP API into a standard Interface, where every endpoint will be represented as a method with some decoration attributes that are part of the Retrofit library.

In this article, I’ll be showing to you a tutorial of how you can connect your app to an API using Retrofit, I’ll be using a free public API to retrieve list of regions, and under each region the list of countries, for each country, some details like sub-region name and population, and then we will display this list into a Recycler View.

As the title states, this article is Part 1 – Introduction to Retrofit in Android.

If you think that you already know the rudimentary concepts of Retrofit, you can navigate to the other 2 articles in this series:

Retrofit Tutorial in Android – Part 2 POST Requests

Retrofit Tutorial in Android – Part 3 Request Headers

Beginning the Tutorial

Open your Android Studio, I always recommend that you use the latest stable release of Android Studio, with all updates installed.

Start a new Project, and choose your minimum sdk level that you want , in this tutorial, let’s choose API 17: Android 4.2 (JELLY BEAN Update 2) as the minimum SDK , and API 26: Android 8.0 (Oreo) as the target SDK

If you don’t have the above SDKs, then go to your SDK Manager and install them, otherwise you can just use whatever SDK you have available, but I would not guarantee if the code will perfectly work on whatever SDK you will be targeting or supporting.

But in general, this tutorial is about Retrofit which should fit well on all SDKs starting API 10: Android 2.3 (Gingerbread)

Now, choose an Empty Activity, and then define your activity name and layout name, and finish.

Referencing Retrofit

Open your build.gradle file, and inside the dependencies section add a reference to the latest version of Retrofit is 2.3.0 (until the date of writing the article), as the below:

Note: we are using the syntax implementation instead of compile. This was one of the major changes introduced to Android plugin for gradle starting version 3.0

Creating the API Interface

Then, create a new interface, and name it ILocationsApi

This will include the needed methods which will match the endpoints which we will use within our tutorial to retrieve the regions, countries and country details.

The above method, will retrieve the regions in a List of RegionModel, which is a class that we will define to match the response of the API.

Creating the Data Model

Now, define the RegionModel class, and add one private field that will represent the ‘region’ field from the API, if you want to use a Java field name different than the API field name, then you have to use the annotation @SerializedName .

This annotation comes from the library com.google.json , so you will have to include it in your app’s gradle file, but since we will be using a Converter Factory for retrofit, then the gson annotation will be included within the library, so let’s include the retrofit’s gson converter library:

You can otherwise just name the field as region, then you don’t have to use this annotation.

We are Overriding equals and hashCode , because we will need them later in this tutorial when we load the regions into HashSet, as we need the list of distinct regions.

Since now we have the Retrofit interface and the RegionModel defined, we will need to create our Retrofit instance to use it to call the endpoint that will retrieve the regions using our interface method.

Create Retrofit Instance inside ApiManager

The best way to create the Retrofit instance is by using an API Manager with a single instance method (singleton), which will guarantee that we only have one instance of the Retrofit throughout the lifetime of our running app, and the creation of this instance will happen once the application starts.

Here is how:

As you can see, the getRegions method returns void. Why? because we want to do an asynchronous call with a callback that we will pass it from our main activity. the callback will handle the response from the API.

Extend Application Class

The application class is the base class that contains all activities and services in the android app. It serves as the entrance to your app as well as a global application state container

You can create another Class that inherits (extends) from the Application Class, however, you need to make sure that you call the new class in your AndroidManifest.xml file, in the <application tag android:name=”.YourNewApplicationClassName”

Extending the Application class, enables you to define some injection configurations, analytics or logging configurations. As such configurations usually come at an initial phase, upon starting the app.

Now back to our tutorial, let’s extend the Application Class, by another class with name ‘MainApplication’ , and in the onCreate method we will create/get the instance to the Api Manager. See below:

This will guarantee that the retrofit instance will be created only once, at the start of the app, and will remain a single instance all through the lifetime of the app.

In Retrofit, you can easily choose between doing synchronous or asynchronous calls.

Synchronous calls , using the execute method, will block the thread that it is running in, and will resume once an HTTP response is returned from call (either if it was a 200 ok, or 400 bad request, or 500 internal server error).  For the full list of HTTP response codes and their meanings, see here ). You cannot do synchronous network call on MainThread or the UI Thread, as it will result in a NetworkOnMainThreadException.

Asynchronous calls, will do the network call on a separate thread, the Main Thread will not be blocked.

Retrofit makes it super easy for you, by providing you the enqueue method. This automatically handles the threading part for you, you only have to handle the result of the network call, with providing the Callback<T> instance.

If the network call you are doing has to block the UI, then you can display a loading dialog to let the user know that there is a process being done, and you can make it not cancellable, so the user won’t be able to cancel the request.

This is useful whenever you are dealing with saving some information into db or doing a payment transaction.

So, back to our tutorial, now we need to populate the list of regions and display them nicely on a RecyclerView.

Creating the Adapter for the RecyclerView

A RecyclerView requires an adapter and a view, so let’s define our adapter that will hold the regions collection, and it will bind each region to a separate view inside this adapter.

So let’s create our RecyclerView adapter and call it ‘RegionsAdapter’:

To explain the above code: the constructor accepts a Context object, and a List of regions . The context is used a source for the layout inflator to inflate the region item layout to be used in the ViewHolder. The list of regions is the data-set that will be used in the onBindViewHolder method to bind each region to the viewHolder’s view and set the needed layout widgets, like the textedit, and the list of regions will also be used to calculate the item count  for the recycler view

Creating the Layout for ReyclerView Item

The region_item layout needs to be defined as the below:

Referencing and Adding the RecyclerView

Now we have our adapter and item defined, let’s go and create our RecyclerView inside the main activity.

The RecyclerView comes inside the android’s v7 support library, and it should be referenced separately:

Sync the project, then open the main activity’s layout file to add the RecyclerView widget:

Calling getRegions Method in MainActivity

Then open the main activity class, and in the onCreate method, get a reference to the RecyclerView widget, and then call the getRegions method from the static instance apiManager from MainApplication:

Let’s understand the code:

after obtaining a reference to the recycler view widget, we do the API call using our previously defined method, getRegions

As you remember earlier in this tutorial, this method takes a callback object as a parameter, so here whenever you call it, you need to define your callback object.

The callback object overrides 2 methods: onResponse and onFailure.

onResponse occurs whenever the api returns a response, regardless if it was valid or not. it might be a 200 ok , 400 bad request, 500 internal server error , or any of the http response codes.

onFailure occurs whenever there was a connectivity issue that prevented from doing the api call, like no network available or socket was closed due to timeout. In our case, we are showing a toast message.

In the onResponse method, we are checking if the API response was successful (200 ok) , if yes, then we are taking the response.body, and using it to extract the regions information, and put them within a list, and then filter them for distinct values, using the HashSet, and next passing them to the RegionsAdapter that we have created previously, and after that we set the recycler view.

The RecyclerView requires a LayoutManager to understand how to arrange the items inside it. So we create a LinearLayoutManager and assign it to the LayoutManager of the RecyclerView.

Adding Internet Permission

For retrofit to be able to connect to the internet via your app, it will require to obtain the internet permission. So you will have to specify this permission in your manifest file:

Even though we are targeting API level 26, the permission we are requesting here is categorized under the safe or normal permissions, that do not require the user’s deliberate consent to approve or reject the permission, and therefore no specific runtime permission code needs to be added to use Retrofit.

Running the App

Now if you run the app, you should see the list of regions displayed properly on the screen once the app starts:

retrofit regions screenshot

If you noticed, there was a little delay before we saw the list of regions on screen, this is the network delay, until the request was done, and a response got returned.

Adding a ProgressBar

Whenever doing an API call, it is really important to let your users know that you are doing an API call, in a friendly way, upon loading a screen or pressing a button. This can be achieved by displaying a progress bar or a loading dialog with a short message.

So, let’s include a ProgressBar widget into our example without displaying it initially:

Then in the code we will take a reference to this progress bar and display it whenever we do the API call, and then hide it whenever the API returns a response or fails. See the below:

And in case of failure. We will also hide it:

When you run the app, you will see a progress loader spinning for a few seconds (depending on how long the network call will take), then the regions will be displayed:

retrofit loading spinner

 

Loading the countries

After we have populated the list of regions, we would like to load the countries of each region inside another activity.

So, to do this task, first we will need to add a new method under ILocationsApi ,which is getCountries, and this time we will pass the region name

Creating the CountryModel

Then open ApiManager, and add a new method, give it the same name, getCountries, with 2 arguments: one for the regionName as a String, and the other for the callback object.

Enabling Click Event on Region Item inside Regions Adapter

Now we need to do few changes on the RegionsAdapter to enable the click event on the Recycler View items ( regions).

On the RegionsAdapter constructor, add a new OnClickListener paramter, and then in the onBindViewHolder method set the click listener of the viewHolder’s itemView to be the listener that you have passed via the constructor.

the itemView is an object of type View, that is defined inside the RegionViewHolder object, therefore, you will be able to assign a click listener to it using its method setOnClickListener. This means we are registering the click listener that we have passed from the MainActivity to the Region Item, so whenever you press on a given region, you will be able to tell which region was pressed and therefore grab some important details from it , like the region name.

Below is the final look of RegionsAdapter Class:

Then in the MainActivity, create the onClick listener, and inside it get a reference to the region_name TextView, grab the text of it, and call the getCountries endpoint:

Now let’s create the other activity, name it CountriesActivity

Inside it, we will read the countries list that was passed through the intent, and we will read the selected region name.

We will display former inside a recycler view, the same way we did for the regions list. And the latter will be used to display a proper title according to the selected region, like ‘Countries in Europe’

The below code the CountriesActivity:

And here is the xml layout for the countries_activity.xml

And the CountriesAdapter is the following:

And here is the xml layout for the country_item.xml

Never forget to add the new Activity to the manifest, otherwise you will get an error at runtime.

 

Your AndroidManifest.xml file should finally look like the below:

 

Running the App

retrofit press region

Then once the loading is done, the new activity will open, and it will display the selected region’s countries in a RecyclerView that can be scrolled.

retrofit countries

 

Next Tutorial

In this tutorial I explained how to use Retrofit to easily build an app that connects to an HTTP-based service with the use of GET method to retrieve data and display them nicely on the screen.

In the upcoming tutorial, I will explain to you how can you use Retrofit to do POST requests,

and then on a subsequent tutorial I will show you how to pass a request header (either using annotations or via an interceptor), also we will explore the different properties of the Retrofit builder to understand the features that are available

Stay tuned!

If you like this article, use the social media buttons to share it in your network.

 

You can check my other Android related articles:
 

Bonus

My amazing reader and learner, listen to this wonderful piece of music that will captivate your brain while you immerse yourself while trying the code examples mentioned in this tutorial.

String Quintet in E Major, Op.11 No.5 – by Luigi Boccherini

Enjoy 🙂

8 Comments on “Retrofit Tutorial in Android – Part 1 Introduction”

  1. Hello Aram,

    Kudos! Its a very well written article to help understand Retrofit in an easy way. I have doubts on two scenarios
    1. what is the Application Class , its not shown here? ( i want to know about onCreate method in MainApplication class here)
    2. If I don’t want to pass all the data as intent extra, how do you propose I make an api call in second activity?

  2. I just found out application is an inbuilt class for all apps. My apologies for not knowing this. That said i still would like to know how to make api calls in different activities if i dont want to pass information as intent extra.
    Many Thanks

    1. Thank you for your comments Henna. No worries at all, maybe I should have explained more regarding the Application class, I made an assumption that all might know about it, but anyway, I’ve added a brief explanation about Application class, I hope it helps.
      If you want to do the API call in CountriesActivity, without passing the countries list as intent, you can just move the api call from the onClick method on MainActivity, to onCreate method in CountriesActivity, and then you should put the countries adapter creation code inside the onResponse method, once you are sure you have the 200 ok.
      In a more advanced scenarios, whenever your app needs to refresh data more often, then you will have to split the adapter creation from changing the dataset, in this case, you will have to introduce a setMethod in your adapter class, that will take the dataset (list), as parameter, and inside it you set the field, and then call notifyDataSetChanged() to let the adapter update the recycler view with your new changes.
      I hope this helps. Thanks 🙂

    1. Thank you for noticing this. I added more explanation on that part, and included the full source code for the RegionsAdapter after inserting the listener. I hope this is clearer now.

    1. Thank you Madhan for your kind feedback, I am glad you’ve found the tutorial useful, feel free to share it among your network and stay tuned for more tutorials.

Leave a Reply