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:
- 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
. - Enter
models
as the package name and clickOK
. - Right-click on the newly created
models
package and selectNew
>Java Class
. - Enter
Todo
as the class name and clickOK
.
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!