A Beginner’s Guide to Retrofit in Android (Java)

Nikhil
6 min readAug 12, 2023

In the world of Android app development, making network requests to fetch data from APIs is a common task. Retrofit is a powerful and popular library that simplifies this process by providing a clean and efficient way to make API calls. In this tutorial, we’ll walk through how to use Retrofit to fetch a list of todos from a mock API and display their titles in a ListView using an ArrayAdapter. For this tutorial, we’ll use the mock API “https://jsonplaceholder.typicode.com/todos".

Step 1: Add internet permission

Before your Android app can communicate with remote servers or APIs, you need to grant it the necessary permissions. To enable internet access for your app, you’ll need to add the “INTERNET” permission to your app’s AndroidManifest.xml file. Add the following line inside the <manifest> tag:

 <uses-permission android:name="android.permission.INTERNET" />

Step 2: Add the Retrofit library

To add the Retrofit library to your project, you’ll need to open the build.gradle file for your app module. In Android Studio, you can find it by expanding the Gradle Scripts folder.

Once you have the build.gradle file open, you’ll need to add the following dependencies to the dependencies block:

dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
}

The first dependency, implementation 'com.squareup.retrofit2:retrofit:2.9.0', adds the Retrofit library to your project. This library provides the core functionality for making HTTP requests and handling responses.

The second dependency, implementation 'com.squareup.retrofit2:converter-gson:2.9.0', adds a converter for Gson to your project. This converter allows Retrofit to automatically convert JSON data into Java objects using the Gson library.

After adding these dependencies, make sure to sync your project with Gradle by clicking on the Sync Now button that appears in the top right corner of Android Studio.

Step 3: Add a POJO class

After adding the Retrofit and Gson dependencies to your project, the next step is to create a models directory and add a POJO (Plain Old Java Object) class named Todo. This class will represent the data model for a todo item that we’ll be fetching from the API.

Here’s how you can create the models directory and add the Todo class:

  1. In Android Studio, right-click on the com.exmple.yourappname (In my case it is com.exmple.retrofitexample) directory in your app module and select New > Package.
  2. Enter models as the package name and click OK.
  3. Right-click on the newly created models package and select New > Java Class.
  4. Enter Todo as the class name and click OK.

Now you should have a new Todo.java file in the models package. This file will contain the definition of the Todo class.

The Todo class is needed for Retrofit because it defines the data model for the todo items that we’ll be fetching from the API. Retrofit uses this class to automatically convert the JSON data returned by the API into Java objects that we can use in our app.

Todo.java

package com.example.retrofitexample.models;

import androidx.annotation.NonNull;

public class Todo {
private int userId;
private int id;
private String title;
private boolean completed;

// Constructor
public Todo(int userId, int id, String title, boolean completed) {
this.userId = userId;
this.id = id;
this.title = title;
this.completed = completed;
}

// Getters
public int getUserId() {
return userId;
}

public int getId() {
return id;
}

public String getTitle() {
return title;
}

public boolean isCompleted() {
return completed;
}

// Setters
public void setUserId(int userId) {
this.userId = userId;
}

public void setId(int id) {
this.id = id;
}

public void setTitle(String title) {
this.title = title;
}

public void setCompleted(boolean completed) {
this.completed = completed;
}

//The string representation of a Todo is its title
public String toString() {
return this.title;
}
}

In this example, we define four fields in the Todo class: userId, id, title, and completed. These fields correspond to the properties of a todo item in the JSON data returned by the API. I have overridden the toString() method. By overriding the toString() method in this manner, we ensure that when the ArrayAdapter renders the Todo objects in the ListView, it will display the title of the todo instead of the default representation.

Step 4: Create a Retrofit Interface

Next, you’ll need to define an interface that represents the API you want to consume. Create a new Java file, e.g., ApiService.java, and define the interface as follows:

package com.example.retrofitexample;

import com.example.retrofitexample.models.Todo;

import java.util.List;

import retrofit2.Call;
import retrofit2.http.GET;

public interface ApiService {
@GET("todos")
Call<List<Todo>> getTodos();
}

Now that we have our ApiService interface defined, let’s take a closer look at how it works. The getTodos() method is annotated with @GET("todos"), which indicates that it makes a GET request to the relative URL "todos".

The @GET annotation is used to specify the HTTP method and the relative URL for the request. In this case, the HTTP method is GET and the relative URL is "todos". When you execute the request, Retrofit will make a GET request to the base URL of your API, followed by the relative URL specified in the annotation.

The return type of the getTodos() method is Call<List<Todo>>. The Call object represents an HTTP request and response. It provides methods for executing the request synchronously or asynchronously, and for canceling the request.

The generic type parameter of the Call object, in this case List<Todo>, specifies the expected type of the response body. When you execute the request, Retrofit will automatically convert the response body into an instance of this type using a converter.

In this case, since the expected type of the response body is List<Todo>, Retrofit will use a converter to automatically convert the JSON array of todo items returned by the API into a List<Todo>.

Internally, Retrofit uses a dynamic proxy to implement the ApiService interface at runtime. When you create an instance of ApiService using Retrofit.create(ApiService.class), Retrofit generates an implementation of the interface that makes HTTP requests using the annotations and method signatures you defined.

Step 5: Fetch Data using Retrofit

In the previous steps, we’ve laid out the groundwork for using Retrofit to fetch data from an API and designed the model classes to represent the fetched data. Now, it’s time to put all the pieces together and see how we can efficiently fetch and display the todos using Retrofit and ListView.

MainActivity.java

package com.example.retrofitexample;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import com.example.retrofitexample.models.Todo;

import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class MainActivity extends AppCompatActivity {

private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

listView = findViewById(R.id.todosList);
ArrayAdapter<Todo> arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://jsonplaceholder.typicode.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiService apiService = retrofit.create(ApiService.class);
Call<List<Todo>> call = apiService.getTodos();
call.enqueue(new Callback<List<Todo>>() {
@Override
public void onResponse(Call<List<Todo>> call, Response<List<Todo>> response) {
arrayAdapter.addAll(response.body());
listView.setAdapter(arrayAdapter);
Toast.makeText(MainActivity.this, "Todos fetched successfully", Toast.LENGTH_SHORT).show();
}

@Override
public void onFailure(Call<List<Todo>> call, Throwable t) {
Toast.makeText(MainActivity.this, "Error fetching data", Toast.LENGTH_SHORT).show();
}
});
}
}

In this code, I’m fetching a list of todos from the API and displaying their titles in a ListView. Here’s how it works:

First, we’re creating a ListView and an ArrayAdapter to display the list of todos. The ArrayAdapter is initialized with the current context and a layout resource for the list items.

Next, we’re creating a Retrofit instance and configuring it with the base URL of the API and a converter factory for Gson. This allows Retrofit to automatically convert the JSON data returned by the API into Java objects.

we’re then using the Retrofit instance to create an instance of the ApiService interface that we defined earlier. This allows you to make HTTP requests to the API using the methods defined in the ApiService interface.

we’re calling the getTodos() method on the ApiService instance to create a Call object representing the HTTP request. we’re then using the enqueue() method on the Call object to execute the request asynchronously.

When the request completes successfully, the onResponse() method of the Callback is called. In this method, we’re adding all of the todo items returned by the API to the ArrayAdapter and setting it as the adapter for the ListView. We’re also displaying a toast message to inform the user that the todos were fetched successfully.

If there’s an error while executing the request, the onFailure() method of the Callback is called. In this method, we’re displaying a toast message to inform the user that there was an error fetching data.

Output:

Conclusion:

You’ve embarked on a successful journey through using Retrofit to retrieve todos from a mock API and show their titles in a ListView. With Retrofit, the process of networking becomes streamlined and comprehensible. You’ve examined how to define API endpoints, create model classes, and initiate API calls using Retrofit. Armed with this knowledge, you’re equipped to delve deeper into Android app development, handling errors, expanding APIs, and refining user interfaces. Keep coding and keep innovating!

--

--