The latest expert opinions, articles, and guides for the Java professional.

Getting started with Retrofit 2

We’re excited to announce that JRebel For Android 2.0 has landed! If you’re as sick of slow development as we are, click below to check out the latest version of our awesome Android dev tool.


This post was modified from its original version, we’ve rewritten it to include latest Retrofit 2.0+ release

Today, I’ll look at using the Retrofit 2 HTTP client for Java and Android to see how complicated vs. how beneficial it is for my application. Retrofit is one of the amazing tools that Square Inc has released into the open source community. It’s a type-safe HTTP client, both for Android and Java applications.

The main premise behind type-safe HTTP clients is that you only need to worry about the semantics of the queries that you send over the network, rather than the details of how to construct URLs, specify parameters correctly and so forth. Retrofit makes this easy by requiring you to write just a couple of interfaces, and that’s it!

Let’s look at an example of how Retrofit2 works in an Android app. The repository which I’ve added all my code to is available on Github, and as always, the best way to learn is to check it out and tinker with it yourself.

I started with an empty project in Android Studio. Personally, when welcomed with a choice of compatibility options and questions about which API I need to support in my application, I honestly get lost.



The positive thing here, of course, is that we’re just playing with a toy project, so we can boldly select the latest SDK and rush through the new project wizard to get ourselves a glorious, functioning “hello world” Android application.
Here’s the link to the commit if you don’t want to mess with the choices and rather just import the project from Github: Floating button app skeleton.

JRebel for Android blog banner

I always enable JRebel for Android for all projects. It’s packaged as an Android Studio plugin, so enabling it means that I click the custom button to run the app, everything else is taken care of. JRebel for Android is a productivity tool for Android developer that can instantly update code and resources on the running device or emulator. That essentially means that while you’re developing the application, you don’t have to waste the precious time waiting for your application to restart, often losing all the relevant application state on the way. Glorious!

So we quickly got from zero to a functional sample that we can run from the Android Studio. What is even better it’s that the new Android emulator that came with the Android Studio 2.0 is pretty snappy too. Now I see the screen with the MainActivity class active.
Clicking the floating button works and the snackbar comes up. All good, let’s verify that our infrastructure works fine by making a random code change to verify that the code reloading works. The first thing that comes to mind is to change the string value on the snackbar.

FloatingActionButton fab = (FloatingActionButton) findViewById(;
fab.setOnClickListener(new View.OnClickListener() {

  public void onClick(View view) {
    Snackbar.make(view, “Super fast hello world”, Snackbar.LENGTH_LONG)
      .setAction(“Action”, null).show();

Lo and behold, one file save and one button click later we observe the updated code in action on the emulator. Now we’re unstoppable! And by that I mean we’re ready to investigate what Retrofit 2 has to offer.

Retrofit 2 is a type-safe HTTP client for Android (and Java), but first of all, it’s a library, so to use it we need to declare the correct dependencies. That is easy, however, note that we need to depend explicitly on the gson converter to transform the JSON responses to the model classes. It wasn’t the case with Retrofit 1, so be careful.

Add these two lines to the build.gradle file:

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

Then, given that we want our application to access the network we need to declare the INTERNET permission in the Android manifest file. This is pretty straightforward, just add this line to the app/src/main/AndroidManifest.xml file:

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

With these preliminary tasks out of the way, we can look at the actual code. The main idea behind Retrofit is that it’s possible to generate the code to query HTTP services at runtime, requiring the developer to produce just an interface as the “specification.” Imagine we have the following model class:

public class Contributor {

    String login;
    String html_url;

    int contributions;

    public String toString() {
        return login + " (" + contributions + ")";

From this we can create the GithubService interface that will embody our HTTP communication.

public interface GitHubService {
  Call<List<Contributor>> repoContributors(
      @Path(“owner”) String owner,
      @Path(“repo”) String repo);

This is the simplest example, we add the @GET annotation on an interface method and provide the path part of the URL that we want to expose it on. Conveniently, the method parameters can be referenced in the path string so you won’t need to jump through hoops to set those. Additionally, with other annotations you can specify query parameters, POST request body and so on:

  • @Query(“key”) — for GET request query parameter
  • @QueryMap — for the map of parameters
  • @Body — use it with the @POST annotation to provide the query body content.

Now, to use this interface during runtime, we’ll need to build a Retrofit object:

interface GitHubService {
    Call<List<Contributor>> repoContributors(
            @Path("owner") String owner,
            @Path("repo") String repo);

    public static final Retrofit retrofit = new Retrofit.Builder()

I like to use the Retrofit builder in the same interface that contains the queries to the website. This way I’m not tempted to complicate things beyond measure. Yeah, there’s some general configuration in use here. We provide the default converter factory to turn the JSON response objects into Java objects, but it’s better to copy-paste that into every service class you have rather than use a single abstraction only to find out it’s leaking.

With these pieces in place, we just need to perform the network call:

  • the specification of our queries
  • the Retrofit object builder

To create the implementation of the GitHubService interface, instantiate a Call object for the HTTP query which we want to perform and execute the request.

GitHubService gitHubService = GitHubService.retrofit.create(GitHubService.class);
Call<List<Contributor>> call = gitHubService.repoContributors(“square”, “retrofit”);
List<Contributor> result = call.execute().body();

Alternatively, one might choose to schedule the call to happen asynchronously and provide the callback to be executed upon completion.

call.enqueue(new Callback<List<Contributor>>() {
  public void onResponse(Response<List<Contributor>> response, Retrofit retrofit) {
    // handle success

  public void onFailure(Throwable t) {
    // handle failure

Sounds simple enough! Let’s prepare some sort of UI and wire the code in. Following the floating button app template design, we need to change the content_main.xml file. Here’s my take on adding a button to initiate the query and a text area to show the results:

  android:layout_marginBottom="151dp" />

  android:textIsSelectable="false" />

Here’s how the network call code might look on your first try:

Button button = (Button) findViewById(;
button.setOnClickListener(new View.OnClickListener() {
  public void onClick(View view) {
    GitHubService gitHubService = GitHubService.retrofit.create(GitHubService.class);
    Call<List<Contributor>> call = gitHubService.repoContributors(“square”, “retrofit”);
    String result = call.execute().body().toString();
    TextView textView = (TextView) findViewById(;

Naturally, this code won’t work; the Android framework won’t allow you to perform network calls on the UI thread. The UI thread should only handle input from the user. Performing any long blocking operations on this thread will simply make the user experience sluggish.

So, we need to refactor this code by moving the network call to a background thread. With JRebel for Android, this won’t take any time at all. Let’s refactor it to use the enqueue method we looked at above.
Now the code looks like the snippet below and works too:

Button button = (Button) findViewById(;
button.setOnClickListener(new View.OnClickListener() {
  public void onClick(View view) {
    GitHubService gitHubService = GitHubService.retrofit.create(GitHubService.class);
    final Call<List<Contributor>> call =
            gitHubService.repoContributors("square", "retrofit");

    call.enqueue(new Callback<List<Contributor>>() {
        public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) {
            final TextView textView = (TextView) findViewById(;
        public void onFailure(Call<List<Contributor>> call, Throwable t) {
            final TextView textView = (TextView) findViewById(;
            textView.setText("Something went wrong: " + t.getMessage());

That’s it, the code now runs, the text view get’s updated with the result of out HTTP query.


The skeleton app is ready, the code builds and works. Now you are equipped to play with both Retrofit and JRebel for Android. You can change a line of code here and there and see the results of your new code in the running app, without any time-wasting. Try adding a couple of fields to the Contributor class. Replace the text view with a list of proper widgets for every contributor. Change the HTTP endpoint altogether and query another website. The world is your oyster.

In this post, we looked at establishing a minimal skeleton app that uses Retrofit 2 for network calls. The code is available on Github. The best way to utilize this post is to clone the app, import it into Android Studio and play with the code yourself using this post as a quick introduction to the relevant areas to focus on.

In the future, I hope I’ll expand on this skeleton app, adding a dependency injection framework to avoid messing with the UI code, throw in a bit of RxAndroid to process the network queries reactively, and so on. By the way, what are your default goto libraries, that you use in any Android project? Maybe it’ll be interesting to look at those instead. Ping me on Twitter: @shelajev, I’d be happy to chat!

Read next:

Responses (10)

  1. Avatar  


    June 5, 2016 @ 10:42 am

    Hey, nice and short introduction to retrofit!

    The internet permission is required to run the app successfully, i think its worthwhile to mention it, seeing how this is a step by step introduction :)

    I also noticed that the github code uses butterknife to bind the button view, maybe it would be worth mentioning that in this post?

  2. Avatar  

    Oleg Šelajev

    June 6, 2016 @ 11:08 am

    Hi, Simon, thank you for the feedback! And I have to say both points that your raise are excellent.

    The application that’ll perform network calls indeed require the INTERNET permission, I’ve added that step into the body of the post, so the readers won’t miss it.

    About the butterknife for binding the views into the activity class, I need to find a good spot to mention that. However, it’s a huge and kinda tangent topic, so it might be better to avoid the confusion of describing all of it at once. I’ll think where in the text to put it and how much to dive into it.

    I’m planning on writing a more detailed post on the dependency injection with Dagger and how sometimes the Butterknife is enough for all your needs. So maybe it’ll just be the new full post and a link from this one.

  3. Avatar  


    June 13, 2016 @ 7:29 am

    hello OLEG SHELAJEV, this a super tutorial, this really really help me, i want to ask, this my json…

    “posts”: [{
    “id”: 16205,
    “type”: “post”,
    “slug”: “”,
    “url”: “”,
    “status”: “publish”,
    “title”: “”,
    “title_plain”: “”
    “date”: “2016-06-09 14:50:49”,
    “modified”: “2016-06-09 14:52:03”,
    “categories”: [{
    “id”: 30,
    “slug”: “sedekah”,
    “title”: “Sedekah”,
    “description”: “”,
    “parent”: 0,
    “post_count”: 132

    my questions is : how to call “get” :
    1. title_plain
    2. date
    3. categories

    same with your example, number 1 in Callback i tried call with this : judul.setText(response.body().getPosts().getTitle));

    this not works….

    and one more question, whether this concept can make recyclerview dynamically?

    i hope you can response,,,, thx a lot buddy….

  4. Avatar  

    Oleg Šelajev

    June 15, 2016 @ 9:46 am

    Hi, what IDE are you using? Response::body() returns the result of the network call, so if you declare the get method in the retrofit interface like:

    Call<List> repoContributors(
    @Path(“owner”) String owner,
    @Path(“repo”) String repo);

    then the response.body will be of the List type.
    List body = response.body();
    So you don’t need to call body.getPosts().getTitle(), just do something like:
    response.body().iterator().next().getTitle(), or iterate the body() result.

    I’m not sure what do you mean if this can make the recyclerview dynamically, so unfortunately, I cannot help you with that.

  5. Avatar  

    Neel prajapati

    June 24, 2016 @ 11:12 am

    hello olge which annonation i have to used In GET method for forgot password??

  6. Avatar  

    Adam Gardner

    June 27, 2016 @ 5:21 pm

    How would you parse something that is like? The nested arrays and all that is really confusing.

    [[{“42599992340201506168072216”:{“TransactionHeader”:{“PartnerCode”:”NAI_ABS_PDN”,”AppId”:”92451ded-6bac-473b-89c8-43895794678d”,”CustomerCodeMPerks”:”42599992340″,”TransactionNumber”:”Testting_Email1″,”TransactionEndDateTime”:”2015-06-17T07:22:16″,”TransactionType”:”Checkout”,”TransactionSubType”:”Sale”,”StoreCode”:”8001″,”RegisterCode”:”1″,”CustomerCode”:”42599992340″,”CustomerCodeType”:”LoyaltyNumber”,”DeliveryPreference”:”email”,”DigitalReceiptEmail”:””,”Cashier”:”Cashier”,”TransactionTotal”:”40.42″,”TransactionSubTotal”:”39.62″,”TaxTotal”:”.80″,”CustomAttributes”:{“item”:[{“key”:”OperatorNumber”,”value”:”101″}]}},”LineDetailList”:{“LineDetail”:[{“ItemLineNumber”:”1″,”ItemCode”:”3600011417″,”Price”:”9.99″,”ExtendedPrice”:”9.99″,”ScanCode”:”036000114171″,”ItemType”:”0″,”DepartmentNumber”:”2″,”OriginalUnitRetail”:”16.99″,”TaxableFlag”:”TRUE”,”VoidFlag”:”FALSE”,”ReasonCode”:”0″,”DiscountList”:{“LineDiscount”:[{“DiscountCode”:”1234567″,”DiscountAmount”:”-700″,”ExtendedDiscountAmount”:”-700″,”DiscountSequence”:”1″,”ItemCode”:”3600011417″,”DiscountType”:”3″,”VoidFlag”:”FALSE”,”DiscountReasonType”:”=> 9.99 Sale PREFERRED SAVINGS”}]},”CustomAttributes”:{“item”:[{“key”:”PrintCategory”,”value”:”GROCERY”},{“key”:”ItemizerText”,”value”:”T”},{“key”:”ItemDescription”,”value”:”VIVA PAPER TOWELS”}]}},{“ItemLineNumber”:”2″,”ItemCode”:”4400000459″,”Price”:”5.99″,”ExtendedPrice”:”5.99″,”ScanCode”:”044000004590″,”ItemType”:”0″,”DepartmentNumber”:”1″,”OriginalUnitRetail”:”5.99″,”TaxableFlag”:”FALSE”,”VoidFlag”:”FALSE”,”ReasonCode”:”0″,”CustomAttributes”:{“item”:[{“key”:”PrintCategory”,”value”:”GROCERY”},{“key”:”ItemizerText”,”value”:”F”},{“key”:”ItemDescription”,”value”:”GRHM CRKS”}]}},{“ItemLineNumber”:”3″,”ItemCode”:”4400000459″,”Price”:”5.99″,”ExtendedPrice”:”5.99″,”ScanCode”:”044000004590″,”ItemType”:”0″,”DepartmentNumber”:”1″,”OriginalUnitRetail”:”5.99″,”TaxableFlag”:”FALSE”,”VoidFlag”:”FALSE”,”ReasonCode”:”0″,”CustomAttributes”:{“item”:[{“key”:”PrintCategory”,”value”:”GROCERY”},{“key”:”ItemizerText”,”value”:”F”},{“key”:”ItemDescription”,”value”:”GRHM CRKS”}]}},{“ItemLineNumber”:”4″,”ItemCode”:”2840008314″,”Price”:”4.99″,”ExtendedPrice”:”4.99″,”ScanCode”:”028400083140″,”ItemType”:”0″,”DepartmentNumber”:”1″,”OriginalUnitRetail”:”4.99″,”TaxableFlag”:”FALSE”,”VoidFlag”:”FALSE”,”ReasonCode”:”0″,”CustomAttributes”:{“item”:[{“key”:”PrintCategory”,”value”:”GROCERY”},{“key”:”ItemizerText”,”value”:”F”},{“key”:”ItemDescription”,”value”:”TOSTITOS”}]}},{“ItemLineNumber”:”5″,”ItemCode”:”3890000473″,”Price”:”2.19″,”ExtendedPrice”:”2.19″,”ScanCode”:”038900004736″,”ItemType”:”0″,”DepartmentNumber”:”1″,”OriginalUnitRetail”:”2.19″,”TaxableFlag”:”FALSE”,”VoidFlag”:”FALSE”,”ReasonCode”:”0″,”CustomAttributes”:{“item”:[{“key”:”PrintCategory”,”value”:”GROCERY”},{“key”:”ItemizerText”,”value”:”F”},{“key”:”ItemDescription”,”value”:”DOLE PINEAPPLE”}]}},{“ItemLineNumber”:”6″,”ItemCode”:”2460001088″,”Price”:”2.99″,”ExtendedPrice”:”2.99″,”ScanCode”:”024600010887″,”ItemType”:”0″,”DepartmentNumber”:”1″,”OriginalUnitRetail”:”2.99″,”TaxableFlag”:”FALSE”,”VoidFlag”:”FALSE”,”ReasonCode”:”0″,”CustomAttributes”:{“item”:[{“key”:”PrintCategory”,”value”:”GROCERY”},{“key”:”ItemizerText”,”value”:”F”},{“key”:”ItemDescription”,”value”:”MORTON SEA SALT”}]}},{“ItemLineNumber”:”7″,”ItemCode”:”2800021168″,”Price”:”4.49″,”ExtendedPrice”:”4.49″,”ScanCode”:”028000211684″,”ItemType”:”0″,”DepartmentNumber”:”3″,”OriginalUnitRetail”:”4.49″,”TaxableFlag”:”FALSE”,”VoidFlag”:”FALSE”,”ReasonCode”:”0″,”CustomAttributes”:{“item”:[{“key”:”PrintCategory”,”value”:”HOME HEALTH BEAUTY”},{“key”:”ItemizerText”,”value”:”F”},{“key”:”ItemDescription”,”value”:”NES CANDY”}]}},{“ItemLineNumber”:”8″,”ItemCode”:”85229800203″,”Price”:”2.99″,”ExtendedPrice”:”2.99″,”ScanCode”:”852298002033″,”ItemType”:”0″,”DepartmentNumber”:”13″,”OriginalUnitRetail”:”2.99″,”TaxableFlag”:”FALSE”,”VoidFlag”:”FALSE”,”ReasonCode”:”0″,”CustomAttributes”:{“item”:[{“key”:”PrintCategory”,”value”:”PRODUCE”},{“key”:”ItemizerText”,”value”:”F”},{“key”:”ItemDescription”,”value”:”STRWBRY 1LB”}]}}]},”TaxDetailList”:{“TaxDetail”:[{“TaxAmount”:”.80″,”TaxCode”:”1″,”CustomAttributes”:{“item”:[{“key”:”TaxDescription”,”value”:”TAX 1 8.000%”}]}}]},”TenderDetailList”:{“TenderDetail”:[{“TenderNumber”:”1″,”TenderCode”:”175″,”TenderAmount”:”40.42″,”BalanceAmount”:”0″,”TenderType”:”Cash”,”CurrencyCode”:”USD”,”MethodOfEntry”:”Keyed”}]},”PrintReceipt”:{“Width”:42,”PrintedReceipt”:”\x1b[KC:KnifeCutn\x1b[BM:PRINT DOWNLOADABLE,NULL,CENTER,NORMALn n 11 Prod Lanen Las Vegas, NV 55344n Phone # 952-828-4000n Store Director – Denise Prodn nCashier:Cashiern n06/17/15 07:20:48n n n PREFERRED CUSTOMER: XXXXXXX2340n\x1b[11mGROCERYn VIVA PAPER TOWELSPC 3600011417 16.99 Tn => 9.99 Sale PREFERRED SAVINGS -7.00 Tn GRHM CRKS 4400000459 5.99 Fn GRHM CRKS 4400000459 5.99 Fn TOSTITOS 2840008314 4.99 Fn DOLE PINEAPPLE 3890000473 2.19 Fn MORTON SEA SALT 2460001088 2.99 Fn\x1b[11mHOME HEALTH BEAUTYn NES CANDY 2800021168 4.49 Fn\x1b[11mPRODUCEn STRWBRY 1LB 85229800203 2.99 Fn SUBTOTAL 39.62n TAX 1 8.000% .80n\x1b[11m TOTAL 40.42n Cash TENDER 40.42n Cash CHANGE .00n n NUMBER OF ITEMS 8n n *********** SAVINGS SUMMARY ***********n PREFERRED SAVINGS 1 7.00n n ****************************************n TODAY’S TOTAL SAVINGS 7.00n THAT IS A SAVINGS OF 15%n ****************************************n n nTrx:2 Oper 101 Term: 1 Store: 8001n06/17/15 07:22:16n n n Thank You For Shopping Atn IMW Southern Calif.”},”TrailerMessageList”:{“TrailerMessage”:[{“MessageSequence”:1,”Message”:”PREFERRED SAVINGS”},{“MessageSequence”:2,”Message”:”Count: 1″},{“MessageSequence”:3,”Message”:”Amount: 7.00″},{“MessageSequence”:4,”Message”:”*********** SAVINGS SUMMARY ***********”},{“MessageSequence”:5,”Message”:”Combined Savings 1 7.00″},{“MessageSequence”:6,”Message”:”****************************************”},{“MessageSequence”:7,”Message”:”TODAY’S TOTAL SAVINGS 7.00″},{“MessageSequence”:8,”Message”:”THAT IS A SAVINGS OF 15%”},{“MessageSequence”:9,”Message”:”****************************************”},{“MessageSequence”:10,”Message”:”Thank You For Shopping At”},{“MessageSequence”:11,”Message”:”IMW Southern Calif.”}]}}}]]

    I keep getting the JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $

    I have made my callback for retrofit a List and same in the onResponse but still keep gettign the error.

  7. Avatar  


    July 11, 2016 @ 7:46 pm

    how to implement the POST method in your code. can you please show an example on how call the POST?

  8. Avatar  

    Neon Warge

    July 15, 2016 @ 6:05 am

    login is always null for me. I don’t know why. Any idea?

    I checked the Github API v3 and it states there that the URI is correct. We are targeting `repos/owner/repo/contributors`. But login is always assigned null.


  9. Avatar  

    Neon Warge

    July 15, 2016 @ 7:05 am

    Oh crap, its because I name my login variable as mLogin. I should name my variables the same with what is indicated from the docs, hence `login`, `html_url`

  10. Avatar  

    Muhammad Salma Nabila Alibasyi

    October 4, 2016 @ 2:46 pm

    hi Oleg Shelajev, nice tutorial for this !
    I wanna ask, how to post / show marker polyline map using json encode from mysql database? I have latitude & longitude each ID in json encode but i don’t know to code it

RSS feed for comments on this post.

Leave a comment