Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Android

Retrofit - A REST Client for Android (Retrofit 2.X)

0.00/5 (No votes)
20 Aug 2019CPOL4 min read 13.2K  
Developing an Android application using Retrofit to connect to an API

Introduction

In this tutorial, we’re going through the basics of Retrofit and creating an Android client for HTTP requests against the GitHub API.

Background

Retrofit is a REST Client for Java and Android. With Retrofit, you can retrieve and/or upload JSON (or other structured data) via a REST based webservice through your Android mobile application very easily.

In this tutorial, we’re going through the basics of Retrofit and creating an Android client for HTTP requests against the GitHub API.

  • Following are the implementation steps
  • Create an Android project
  • Define Gradle dependencies
  • Define Android’s Network Permission
  • Describe API Endpoints
  • Create the UI
  • Configure JSON mapping
  • Create the Retrofit client
  • Execute request and display data

Using the Code

Create an Android project with your preferred IDE. I will be using Android Studio. You can create an empty activity project.

Image 1

Select the build.gradle (module) file under Gradle Scripts section and specify Retrofit as a dependency for your project.

JavaScript
dependencies { 
     //Other dependencies...
    // Retrofit & OkHttp dependency
    implementation 'com.squareup.retrofit2:retrofit:2.5.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
}

Click on the Sync Now link after adding the dependencies.

Image 2

The build system will download and provide the necessary library when you run the command to build your code.

Note: Retrofit 2 (by default) is included with OkHttp as the networking layer. Therefore, you don’t need to explicitly define OkHttp as a dependency for your project. But Retrofit 2 requires a dependency for the automatic conversion of request and responses. The default converter is Gson. Gson is a very powerful library to map data structures represented as JSON to Java objects.

Define Android’s Network Permission

Android applications are designed to run inside sandboxed environments. Retrofit performs HTTP requests against APIs which are running on servers in the Internet. In order to execute such external requests from an Android application, it is required to have Internet permission to open network sockets. Therefore, you need to define these permissions inside the AndroidManifest.xml file.

JavaScript
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="app.retrofit.nipunu.retrofitapp">
   <uses-permission android:name="android.permission.INTERNET" />
   <application
       ...

Describe API Endpoints

In order to send requests, first you need to describe the API endpoints. In this tutorial, we’ll describe a simple GitHub API endpoint.

Create an interface named GitHubClient inside your application source set.

Image 3

Image 4

Select interface as the ‘kind’ and click OK.

Image 5

Now you should have your interface created.

Image 6

Define a method named UserRepositories which takes a parameter of type string which will be the user name. This method will return a RepoList type list.

C#
public interface GitHubClient {
   List<RepoList> UserRepositories(String phrase);
}

Since we are issuing a Get request to retrieve the results, we need to annotate our method with the endpoint as follows. The @GET annotation declares that this request uses the HTTP GET method.

JavaScript
import retrofit2.http.GET;
public interface GitHubClient {
   @GET("users/USER_NAME/repos")
   List<RepoList> UserRepositories(String phrase);
}

Instead of hard coding the user name, we can use Retrofit’s path parameter replacement functionality as follows:

C#
import retrofit2.http.Path;
public interface GitHubClient {
   @GET("users/{username}/repos")
   List<RepoList> UserRepositories(@Path("username") String userName);
}

Currently, the UserRepositories is a synchronous method, which will freeze the UI and crash the app for Android 4.0 or later. As a rule, network requests from the UI thread need to happen asynchronously. We can make this method call asynchronous easily by wrapping the method return inside a call<> object as follows:

JavaScript
public interface GitHubClient {
   @GET("users/{username}/repos")
   Call<List<RepoList>> UserRepositories(@Path("username") String userName);
}

The complete GitHubClient is as follows:

JavaScript
import java.util.List;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;
public interface GitHubClient {
   @GET("users/{username}/repos")
   Call<List<RepoList>> UserRepositories(@Path("username") String userName);
}

We still did not implement the RepoList class. Let's go and add the RepoList class to our application.

Create a class named RepoList. This class is used to map with the return data. In this case, we only match the name of the repository.

JavaScript
public class RepoList {
   private String name;
   public String getRepoName(){return name;}
}

Create the UI

We need a UI to display the results. Let's use a ListView control to display the names of the repositories which we receive as result.

Remove the default Textview in the activity_mail.xml file and create a ListView control with the id repository_list. Set constraints to fill the entire activity’s space by the ListView.

Image 7

Reference the Listview inside the MainActivity.class file’s onCreate method.

JavaScript
public class MainActivity extends AppCompatActivity {
   private ListView repositoryList;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       repositoryList = (ListView)findViewById(R.id.repository_list);
   }
}

Now we need to create a Layout to hold a single item of the ListView, which is the name of the repository in our case.

Create a new layout called repository_list_item.xml. Add a TextView inside that layout and name it repository_name_text.

XML
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent">
   <TextView
       android:id="@+id/repository_name_text"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_marginStart="8dp"
       android:layout_marginTop="8dp"
       android:layout_marginEnd="8dp"
       android:layout_marginBottom="8dp"
       android:text="TextView"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

The ListView needs an adapter to load data. Let's create the adapter class.

Create a class named RepoListAdapter which extends from ArrayAdapter of type RepoList.

JavaScript
import android.widget.ArrayAdapter;
public class RepoListAdapter extends ArrayAdapter<RepoList> {
   Context context;
   List<RepoList> repoList;
}

Add a constructor to the class.

JavaScript
public RepoListAdapter(Context context, List<RepoList> repoList) {
   super(context, R.layout.repository_list_item,repoList);
   this.context = context;
   this.repoList = repoList;
}

Finally, override the getView method to retrieve every repo name and set that to the TextView.

JavaScript
@Override
public View getView(int position, View convertView, ViewGroup parent) {
   View row = convertView;
    if (row == null) {
        LayoutInflater inflater =
                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        row = inflater.inflate(R.layout.repository_list_item, parent, false);
    }
    TextView textView = (TextView) row.findViewById(R.id.repository_name_text);
    RepoList list = repoList.get(position);
    String repoName = list.getRepoName();
    textView.setText(repoName);
    return row;
}

Now inside the MainActivity’s onCreate method, let's instantiate the Retrofit builder class. This class is responsible for creating the Retrofit object for us.

JavaScript
@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
   repositoryList = (ListView) findViewById(R.id.repository_list);
   Retrofit.Builder builder = new Retrofit.Builder()
       .baseUrl("https://api.github.com")
       .addConverterFactory(GsonConverterFactory.create());
}

Next, inside the same onCreate method, let's create the Retrofit object with the help of the builder and make the API call.

JavaScript
@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
   repositoryList = (ListView) findViewById(R.id.repository_list);
   Retrofit.Builder builder = new Retrofit.Builder()
           .baseUrl("https://api.github.com")
           .addConverterFactory(GsonConverterFactory.create());
   Retrofit retrofit = builder.build();
   GitHubClient client = retrofit.create(GitHubClient.class);
   Call<List<RepoList>> call = client.UserRepositories("USER_NAME");
}

The above call is an asynchronous method call. Therefore, we need to utilize that call asynchronously via enqueue method as a new callback.

JavaScript
call.enqueue(new Callback<List<RepoList>>() {
   @Override
   public void onResponse(Call<List<RepoList>> call, Response<List<RepoList>> response) {      
   }
   @Override
   public void onFailure(Call<List<RepoList>> call, Throwable t) {
   }
});

We need to implement the onResponse and onFailure methods as the final steps.

JavaScript
call.enqueue(new Callback<List<RepoList>>() {
   @Override
   public void onResponse(Call<List<RepoList>> call, Response<List<RepoList>> response) {
       List<RepoList> list = response.body();
       repositoryList.setAdapter(new RepoListAdapter(MainActivity.this,list));
   }
   @Override
   public void onFailure(Call<List<RepoList>> call, Throwable t) {
       Toast.makeText(MainActivity.this, "Error...!!!", Toast.LENGTH_SHORT).show();
   }
});

Now run the application.

History

  • 20th August, 2019: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)