× Home Tutorials Training Consulting Products Books Company Donate Contact us









NOW Hiring

Quick links

Share

This tutorial explains the usage of the Retrofit library as REST client.

1. Retrofit

Retrofit is a REST Client for Android and Java by Square. It makes it relatively easy to retrieve and upload JSON (or other structured data) via a REST based webservice. Retrofit can be configured with converter is used for its data serialization. Typically for JSON you use GSon, but you can add custom converters to process XML or other protocols. Retrofit uses the OkHttp library for HTTP requests.

Retrofit allows to use the following converters:

  • Gson: com.squareup.retrofit:converter-gson

  • Jackson: com.squareup.retrofit:converter-jackson

  • Moshi: com.squareup.retrofit:converter-moshi

  • Protobuf: com.squareup.retrofit:converter-protobuf

  • Wire: com.squareup.retrofit:converter-wire

  • Simple XML: com.squareup.retrofit:converter-simplexml

To work with Retrofit you need basically three classes.

  • Model class which is used to map the JSON data to

  • Interfaces which defines the possible HTTP operations

  • Retrofit.Builder class - Instance which uses the interface and the Builder API which allows defining the URL end point for the HTTP operation.

1.1. Define HTTP operations through interfaces

Every method of an interface represents one possible API call. It must have a HTTP annotation (GET, POST, etc.) to specify the request type and the relative URL. The return value wraps the response in a Call object with the type of the expected result.

@GET("users")
Call<List<User>> getUsers()

To dynamically change the URL Retrofit supports replacement blocks and query parameters. A replacement block is added to the relative URL with {}. With the help of the @Path annotation on the method parameter, the value of that parameter is bound to the specific replacement block.

@GET("users/{name}/commits")
Call<List<Commit>> getCommitsByName(@Path("name") String name)

Query parameters are added with the @Query annotation on a method parameter. They are automatically added at the end of the URL.

@GET("users")
Call<User> getUserById(@Query("id") Integer id)

The @Body annotation on a method parameter tells Retrofit to use the object as the request body for the call.

@POST("users")
Call<User> postUser(@Body User user)

You can generate Java objects based on JSON via the following URL: http://www.jsonschema2pojo.org/ This can be useful to create complex Java data structures from existing JSON.

2. Exercise: Using Retrofit to query Gerrit in Java

The following section describes how to create a minimal Java application which uses Retrofit to query the subjects of open changes from the Gerrit API. The results will then be printed on the console.

2.1. Project creation and setup

Create a new Java application with the name GerritJava. Add a new (default) package to src/main/java with the name com.vogella.java.retrofitgerrit.

Add the following dependencies to your build.gradle file.

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.google.code.gson:gson:2.6.1'

2.2. Define the API and the Retrofit adapter

In the JSON reply from Gerrit we are only interested in the subject of the changes. Therefore create the following data classes in the previously added default package.

package com.vogella.java.retrofitgerrit;

public class Change {
        String subject;

        public String getSubject() {
                return subject;
        }

        public void setSubject(String subject) {
                this.subject = subject;
        }
}

Define the REST API for Retrofit via the following interface.

package com.vogella.java.retrofitgerrit;

import java.util.List;

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

public interface GerritAPI {

        @GET("changes/")
        Call<List<Change>> loadChanges(@Query("q") String status);
}

Create the following controller class. This class creates the Retrofit client, calls the Gerrit API and handles the result (prints the result of the call on the console).

package com.vogella.java.retrofitgerrit;

import java.util.List;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

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

public class Controller implements Callback<List<Change>> {

        static final String BASE_URL = "https://git.eclipse.org/r/";

        public void start() {
                Gson gson = new GsonBuilder()
                        .setLenient()
                        .create();

                Retrofit retrofit = new Retrofit.Builder()
                                .baseUrl(BASE_URL)
                                .addConverterFactory(GsonConverterFactory.create(gson))
                                .build();

                GerritAPI gerritAPI = retrofit.create(GerritAPI.class);

                Call<List<Change>> call = gerritAPI.loadChanges("status:open");
                call.enqueue(this);

        }

        @Override
        public void onResponse(Call<List<Change>> call, Response<List<Change>> response) {
                if(response.isSuccessful()) {
                        List<Change> changesList = response.body();
                        changesList.forEach(change -> System.out.println(change.subject));
                } else {
                        System.out.println(response.errorBody());
                }
        }

        @Override
        public void onFailure(Call<List<Change>> call, Throwable t) {
                t.printStackTrace();
        }
}

The last step is to create a class with a main-method to start the controller.

package com.vogella.java.retrofitgerrit;

public class Main {

        public static void main(String[] args) {
                Controller controller = new Controller();
                controller.start();
        }
}

3. Exercise: Using Retrofit to query Stackoverflow in Android

3.1. Target

StackOverflow is a popular side for asking programming orientated questions. It also provides a REST API which is well documented. Queries can be build using this API. You find it documented via the following URL: https://api.stackexchange.com/docs/search In this exercise you query for open questions based on tags with the Retrofit REST library.

We use the following query URL in our example. The tags will be set via our code.

https://api.stackexchange.com/2.2/search?order=desc&sort=activity&tagged=android&site=stackoverflow

3.2. Project creation and setup

Create an Android application called com.vogella.android.retrofitstackoverflow. It should use the com.vogella.android.retrofitstackoverflow top level package name.

Add the following dependency to your build.gradle file.

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'

Add the permission to access the Internet to your manifest file.

3.3. Define the API and the Retrofit adapter

In the JSON reply from StackOverflow we are only interested in the title and the link. Therefore create the following data classes.

package com.vogella.android.retrofitstackoverflow;

// This is used to map the JSON keys to the object by GSON
public class Question {

    String title;
    String link;

    @Override
    public String toString() {
        return(title);
    }
}
package com.vogella.android.retrofitstackoverflow;

import java.util.List;

public class StackOverflowQuestions {
    List<Question> items;
}

Define the REST API for Retrofit via the following interface.

The list structure is needed as stackoverflow wraps its answer in an item object.

package com.vogella.android.retrofitstackoverflow;

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

public interface StackOverflowAPI {
    @GET("/2.2/questions?order=desc&sort=creation&site=stackoverflow")
    Call<StackOverflowQuestions> loadQuestions(@Query("tagged") String tags);
}

Create a XML menu resource similar to the following called main_menu.xml and put it into the menu folder, which you should find in the res folder (create the folder if you could not find it).

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/menu_load"
        android:title="Load" />
</menu>

Change your activity code to allow querying for questions marked with the tag "android".

package com.vogella.android.retrofitstackoverflow;

import android.app.Activity;
import android.app.ListActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
import android.widget.ArrayAdapter;
import android.widget.Toast;

import java.util.ArrayList;

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

public class MainActivity extends ListActivity implements Callback<StackOverflowQuestions> {

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        requestWindowFeature(Window.FEATURE_PROGRESS);
        ArrayAdapter<Question> arrayAdapter =
                new ArrayAdapter<Question>(this,
                        android.R.layout.simple_list_item_1,
                        android.R.id.text1,
                        new ArrayList<Question>());
        setListAdapter(arrayAdapter);
        setProgressBarIndeterminateVisibility(true);
        setProgressBarVisibility(true);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        setProgressBarIndeterminateVisibility(true);
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.stackexchange.com")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        // prepare call in Retrofit 2.0
        StackOverflowAPI stackOverflowAPI = retrofit.create(StackOverflowAPI.class);

        Call<StackOverflowQuestions> call = stackOverflowAPI.loadQuestions("android");
        //asynchronous call
        call.enqueue(this);

        // synchronous call would be with execute, in this case you
        // would have to perform this outside the main thread
        // call.execute()

        // to cancel a running request
        // call.cancel();
        // calls can only be used once but you can easily clone them
        //Call<StackOverflowQuestions> c = call.clone();
        //c.enqueue(this);

        return true;
    }

    @Override
    public void onResponse(Call<StackOverflowQuestions> call, Response<StackOverflowQuestions> response) {
            setProgressBarIndeterminateVisibility(false);
        ArrayAdapter<Question> adapter = (ArrayAdapter<Question>) getListAdapter();
        adapter.clear();
        adapter.addAll(response.body().items);
    }

    @Override
    public void onFailure(Call<StackOverflowQuestions> call, Throwable t) {
        Toast.makeText(MainActivity.this, t.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
    }
}

4. Exercise: Using Retrofit to access Github API in Android

4.1. Project setup

To test Retrofit create an application called Retrofit Github. Use the com.vogella.android.retrofitgithub top level package name.

To use Retrofit in your application, add the following dependency to your build.gradle file

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'

Add the permission to access the Internet to your manifest file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.vogella.android.retrofitgithub" >

    <uses-permission android:name="android.permission.INTERNET"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Add two buttons to your activity_main.xml layout file.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.vogella.android.retrofitgithub.MainActivity">

    <Button
        android:id="@+id/loadRepositories"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Load Repositories"
        android:gravity="center"
        android:layout_alignParentBottom="true"
        android:onClick="onClick"/>

    <Button
        android:id="@+id/loadUserData"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Load user data"
        android:gravity="center"
        android:layout_above="@id/loadRepositories"
        android:onClick="onClick"/>
</RelativeLayout>

Create the following interface and class for the Retrofit API.

package com.vogella.android.retrofitgithub;

// This is used to map the JSON keys to the object by GSON
public class GithubRepo {

    String name;
    String url;

    @Override
    public String toString() {
        return(name + " " +  url);
    }
}
package com.vogella.android.retrofitgithub;

// This is used to map the JSON keys to the object by GSON
public class GithubUser {

    String login;
    String name;
    String email;

    @Override
    public String toString() {
        return(login);
    }
}
package com.vogella.android.retrofitgithub;

import java.util.List;

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


public interface GithubAPI {
    String ENDPOINT = "https://api.github.com";

    @GET("/users/{user}")
    Call<GithubUser> getUser(@Path("user") String user);

    @GET("users/{user}/repos")
    Call<List<GithubRepo>> getRepos(@Path("user") String user);

}
package com.vogella.android.retrofitgithub;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

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 Activity implements Callback<GithubUser> {

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

    }
    public void onClick(View view) {
        Gson gson = new GsonBuilder()
                .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
                .create();
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(GithubAPI.ENDPOINT)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build();
        GithubAPI githubUserAPI = retrofit.create(GithubAPI.class);

        switch (view.getId()) {
            case R.id.loadUserData:
                // prepare call in Retrofit 2.0

                Call<GithubUser> callUser = githubUserAPI.getUser("vogella");
                //asynchronous call
                callUser.enqueue(this);
                break;
            case R.id.loadRepositories:
                Call<List<GithubRepo>> callRepos = githubUserAPI.getRepos("vogella");
                //asynchronous call
                callRepos.enqueue(repos);
                break;
        }
    }


    Callback repos = new Callback<List<GithubRepo>>(){

        @Override
        public void onResponse(Call<List<GithubRepo>> call, Response<List<GithubRepo>> response) {
            if (response.isSuccessful()) {
                List<GithubRepo> repos = response.body();
                StringBuilder builder = new StringBuilder();
                for (GithubRepo repo: repos) {
                    builder.append(repo.name + " " + repo.toString());
                }
                Toast.makeText(MainActivity.this, builder.toString(), Toast.LENGTH_SHORT).show();

            } else
            {
                Toast.makeText(MainActivity.this, "Error code " + response.code(), Toast.LENGTH_SHORT).show();
            }

        }

        @Override
        public void onFailure(Call<List<GithubRepo>> call, Throwable t) {
            Toast.makeText(MainActivity.this, "Did not work " +  t.getMessage(), Toast.LENGTH_SHORT).show();
        }
    };

    @Override
    public void onResponse(Call<GithubUser> call, Response<GithubUser> response) {
        int code = response.code();
        if (code == 200) {
            GithubUser user = response.body();
            Toast.makeText(this, "Got the user: " + user.email, Toast.LENGTH_LONG).show();
        } else {
            Toast.makeText(this, "Did not work: " + String.valueOf(code), Toast.LENGTH_LONG).show();
        }
    }

    @Override
    public void onFailure(Call<GithubUser> call, Throwable t) {
        Toast.makeText(this, "Nope", Toast.LENGTH_LONG).show();

    }
}

Access the following URL in your browser: https://api.github.com/users/vogella and build a data model and interface with the data you are interested in. Read this data via Retrofit and show it in a list.

5. About this website

6. Retrofit resources

6.1. vogella GmbH training and consulting support

TRAINING SERVICE & SUPPORT

The vogella company provides comprehensive training and education services from experts in the areas of Eclipse RCP, Android, Git, Java, Gradle and Spring. We offer both public and inhouse training. Whichever course you decide to take, you are guaranteed to experience what many before you refer to as “The best IT class I have ever attended”.

The vogella company offers expert consulting services, development support and coaching. Our customers range from Fortune 100 corporations to individual developers.

Copyright © 2012-2016 vogella GmbH. Free use of the software examples is granted under the terms of the EPL License. This tutorial is published under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Germany license.

See Licence.