SureshJoshi.com ▼

Android Adventures - Finding the Right RetroFit


2015-09-22

Today, I have the pleasure of announcing my blog’s first guest post! It’s written by Bryan Chu, who is just starting his drive along the sometimes-long, sometimes-crazy, always-fun road of learning to develop Android apps. Having recently come back from Maui, I’m going to retroactively call this the Road to Hana - if you’ve been there, you’ll understand. Speaking of Retro…

Enter Bryan

If you’re reading this post you’re probably at least a little familiar with Android development - which means you’re already way ahead of me. Welcome to ‘Android Adventures’, where everything’s made up and the points could matter depending on your familiarity with Android [SJ: This is the first of many pop-culture quotes].

A little bit about these posts - if you’re a novice just looking for another novice to relate to, welcome to the club. If you’re a seasoned veteran, you better get strapped in for one mild ride. [SJ: As Bryan said, he’s a novice starting Android for the first time - for the sake of his learning, please note that I’ve specifically NOT edited/altered any of his Android code, so if anyone sees any ‘best practices’ that should be implemented - please feel free to code review in the comments!].

About myself – I’ve been coding on and off (poorly) for the last three years. I’ve got a passing familiarity with Java and object-oriented-programming (OOP, there it is), but that’s a good thing because that’s all you’re going to need to follow along.

This week (and the last), I’ve been working on a little project for myself – use RetroFit (an Android library that turns a REST API into a Java Interface) to pull data from GitHub’s public repositories and display that data in a ListView on my Android device. RetroFit is a really neat library that seriously simplifies working with HTTP APIs, and I was really excited to start using it.

For this post, I’ll focus on how I used RetroFit to pull and display data from GitHub’s API into a TextView.

Getting started

First things first (I’m the realest), this is what you’re going to need to get things started – in your app/build.gradle script, add these lines so that your dependencies look like this:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.squareup.retrofit:retrofit:1.9.0'
    compile 'com.google.code.gson:gson:2.3'
    compile 'com.jakewharton:butterknife:7.0.1'
}

Yours might look a little different, but just focus on adding RetroFit (to help with our REST requests), GSON (to help serialize our JSON object), and (optionally) ButterKnife to help us inject bind our views (v7.0.1 does not appreciate injections).

Also, be sure to add the following permission to your AndroidManifest.xml file so that your device can access the Internet (you’re making HTTP requests, after all):

Run a Gradle sync and you’re good.

Some Background

While that’s syncing, let’s take a trip over to https://api.github.com/repositories to get a better understanding of what exactly we’re doing here.

When you open that link in your browser, you should see a long list of properties - ids, names, logins, and more. What you’re seeing is a JSON array, populated with JSON objects (in which each repository is stored). We want to be able to take that data and use it for whatever we’d like (such as displaying information in a TextView).

Speaking of TextViews, let’s replace the XML in our activity_main.xml file with the following (you can find it in your res/layout folder).

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                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=".MainActivity"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:padding="6dip" >
            <TextView
                android:id="@+id/texv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:maxLines = "100"
                android:scrollbars = "vertical"/>
        </RelativeLayout>

The above is just going to give us a text box to print to and something not particularly pretty to look at.

There are four Java classes we’re going to be working with today – one interface (for RetroFit), our data model class (or POJO (Plain Old Java Object) in which we break up and store all the data that GitHub wishes to provide), a custom object to deal with the nested object within the JSON request (another POJO, really), and the Main Activity class containing our onCreate() method.

Let’s start things off with the data model. Before jumping into the code, it would be useful to revisit the JSON object (really an array) that Github’s API is providing on our GET request.

[
    {
    "id": 1,
    "name": "grit",
    "full_name": "mojombo/grit",
    "owner": {
        "login": "mojombo",
        "id": 1,
        "avatar_url": "https://avatars.githubusercontent.com/u/1?v=3",
        "gravatar_id": "",
        ...
    },
    "private": false,
    "html_url": "https://github.com/mojombo/grit",

    ...
]

The actual output goes on and on, so I’ve only shown a small snippet of it above. The ‘[‘ bracket at the top means that this is an array of JSON objects (your code is going to be different, slightly, for single objects). Pay special attention to the “owner” segment – that’s a nested JSON object and we’re going to need to create a custom Java object in order to serialize it.

I called my data model ‘GitModel’. Here’s the code (sans imports and package names, of course):

    public class GitModel {
        @Expose
        private String login;
        @Expose
        private Integer id;
        @Expose
        private String name;
        @SerializedName("full_name")
        @Expose
        private String fullName;

        public String getLogin() {
            return login;
        }
        public void setLogin(String login) {
            this.login = login;
        }
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getfullName() {
            return fullName;
        }
        public void setfullName(String fullName) {
            this.fullName = fullName;
        }
    }

As you can see, this is an archetypal Java object - attributes, and their getters and setters. There is a bit of a twist though - the @Expose and @SerializedName annotations.

The @Expose annotation is part of the GSON library. It signifies that this member should be exposed for serialization. You can also make custom variable names (with @SerializedName), like using ‘fullName’ to represent the full_name attribute in the JSON object.

While ‘login’ and ‘id’ are relatively straightforward, there are some attributes (like ‘avatar_url’) that are found within a nested JSON object, ‘owner’. We aren’t going to be able to just grab it like we did before.

So, how do we make it work? Easy! Just make a custom class for serializing the owner attribute.

    public class Owner {
        @Expose
        private String login;
        @Expose
        private String avatar_url;

        public String getLogin() {
            return this.login;
        }
        public String getAvatar_url() {
            return this.avatar_url;
        }
    }

And @Expose it in our GitModel (as well as add the appropriate getters and setters):

    @Expose
    private Owner owner;
    ...
    public Owner getOwner() {
        return owner;
    }
    public void setOwner(Owner owner) {
        this.owner = owner;
    }

For my application, I wanted the login and the avatar_url, but you can really extend this to any attributes or nested objects that are returned from your JSON request.

Next, we need an interface to use with RetroFit. I called mine GitApi.

public interface GitApi {
    @GET("/repositories")      //here is the other url part for the API
    public void getFeed(Callback<List<GitModel>> response);
}

We want to GET from the /repositories of the Github API using RetroFit. The Callback method is also part of RetroFit and communicates a response (given a response type) from the server.

In this case, given a JSON array, we want to create a List of Java objects for each JSON object in the array - hence: List.

RetroFitting it all together

Now that we’ve got all our pieces, let’s check out the MainActivity class:

public class MainActivity extends ActionBarActivity {
    @Bind(R.id.texv)
    TextView tv;
    String API = "https://api.github.com";                         //BASE URL

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

        ButterKnife.bind(this);
        RestAdapter restAdapter = new RestAdapter.Builder()
                .setEndpoint(API).build();                                        //create an adapter for retrofit with base url

        GitApi git = restAdapter.create(GitApi.class);                            //creating a service for adapter with our GET class

        git.getFeed(new Callback<List<GitModel>>() {
            @Override
            public void failure(RetrofitError error) {
                tv.setText(error.getMessage());
            }

            @Override
            public void success(List<GitModel> GitModel, Response response) {
                //we get json object from github server to our POJO or model class
                tv.setMovementMethod(new ScrollingMovementMethod());
                for (int i = 0; i < GitModel.size(); i++) {
                    tv.append("" + GitModel.get(i).getName() + "\t id: "
                            + GitModel.get(i).getId() + "\t full name: "
                            + GitModel.get(i).getfullName() + "\t Avatar Url: "
                            + GitModel.get(i).getOwner().getAvatar_url() + "\n");
                }
            }
        });
    }
}

Here we use just a teensy bit of ButterKnife, binding our TextView in to our application (it looks so neat and tidy!). Of course, feel free to use the findViewbyID method if you’re more comfortable with it [SJ: I’ve already raved about the awesomeness of ButterKnife - every project I work on, I include it and immediately cleanse my code of those ugly, old-school findViewById calls].

After our ButterKnife shenanigans, the next first thing we do is create a RetroFit RestAdapter, and set our Endpoint to our API (which in this case is GitHub’s). We initialize our data model and create it using the RestAdapter.

Then, we call our gitFeed and get our List response from the API. If the Callback is unsuccessful, we set our TextView to an error message, but if its successful, we pass a List object and the Response from our callback into our ‘success’ method.

That List object takes in the Response, and now we can use it to do stuff! In this case, I wanted the TextView to display the name, the id, the full name, and the Avatar URL (which we’re going to use in our List View for Part 2!) for each of the repositories on the public repo listing, so I simply looped through our List and appended the resultant Strings to our TextView.

That’s that!

Join us next time in Part 2, where we start to incorporate some (slightly) interesting UI elements into our application!

Feature Photo credit: Dave O / Flickr / CC BY-SA