Best Practices for Consuming APIs On Android

First Some History

Up until fairly recently integrating APIs into your Android application had been the wild west. Each application had their own networking and caching implementations that were generally pretty brittle and didn’t handle non optimal networking conditions terribly well.

Thanks largely to Square Inc, the innovative company bringing credit card processing for businesses to mobile phones, there is now a wealth of high quality open source libraries available that support API integration in your Android applications.

What will we learn how to do?

In this post, we will learn how to use a Retrofit, OkHttp and GSON stack in order to be able to simply and robustly integrate a REST API into your application. Using this stack we will download and parse some data from Twitch.tv.  Following the steps outlined, you will be able to integrate most REST APIs into your application in just a few minutes, without writing any boilerplate code.

Lets Learn About the Stack

Retrofit

Retrofit makes it incredibly easy to download JSON or XML data from a web API and parse it into a Plain Old Java Object (POJO). For example to download a users repo information from Github all the code you need to write is:

Additionally you would need to create the Repo POJO so that the parser knows what type of data you are expecting from that endpoint.  This code can be auto-generated, more on this later.

Its just as easy to provide query parameters or do POST or HEAD requests. For instructions for how to connect with different types of APIs just see the documentation.

One of the nice features of Retrofit is the ability to add additional logic to all requests and responses. You could for instance add additional data to all request HTTP headers or intercept any unauthorized response error codes and redirect the user to your login screen.

OkHttp

OkHttp is an HTTP client for Android applications. It is efficient by default and includes support for SPDY, connection pooling, GZIP, and a HTTP response cache.

In addition OkHttp handles common networking issues automatically and silently such as retries and SSL handshake issues. Retrofit will use OkHttp automatically as its networking layer if it is present in your application.

GSON

GSON is a Java library that is used to parse JSON data into a POJO. It can also be used to convert a POJO into JSON, which in Android can be helpful as a way to store generic objects into shared preferences.

To use GSON you essentially just need to create a representative POJO of the data you wish to parse and run GSON on the data to parse it into an instance of the POJO. Its dead simple and makes parsing a breeze. To learn how to create your POJOs compatible with GSON see the documentation. Retrofit uses GSON in order to do its JSON parsing.

Lets do Some Coding!

Add the libraries to your project

  1. Download the jar files for Retrofit, OkHttp, and GSON.
  2. Drag each of the jar files into your libs folder in your project
  3. If using Android Studio Sync the project with gradle

Find or write an API

You probably already have an API in mind but if you are looking for a directory of APIs I recommend ProgrammableWeb. For the purposes of this tutorial we are going to be parsing a list of streams available from Twitch.tv. To see the request format see their API documentation. The basic API request to get the list of steams from Twitch.tv in JSON format is: http://api.justin.tv/api/stream/list.json

Capture Some Sample Output

In order to proceed we need some sample data that is returned from the API. In this case since it is a GET request we can just run the request in a web browser, and copy out the response such as:

[{“broadcast_part”: 4, “featured”: true, “channel_subscription”: true, “audio_codec”: “uncompressed”, “id”: “6640712464”, “category”: “gaming”, “title”: “Fnatic xPeke, Normals(ranked down) on smurf”, “geo”: “DE”, “video_height”: 1080, “site_count”: 8014, “embed_enabled”: true, “channel”: {“subcategory”: null, “producer”: true, “image_url_huge”: “http://static-cdn.jtvnw.net/jtv_user_pictures/xpeke-profile_image-a182a5fe5a8f239b-600×600.jpeg”, “timezone”: “Europe/Madrid”, “screen_cap_url_huge”: “http://static

Generate the POJOs for your data

Now for the fun part, using the sample data we just captured we are going to auto generate the POJOs that represent that data. Use jsonschema2pojo and be sure to enter in your desired package name, class name, JSON as the type, and use primitive types. For this example the generator got confused because the root of the JSON is an array and not an object; so I only pasted in the first element of the array. Some fiddling may be necessary.

POJO-Generator

Integrate the Generated POJOs Into Your Code

With the POJOs generated now we can just paste those generated classes into our project. In my sample project they are in the models package.

Use Retrofit to Download/Parse the API

Create a Rest Adapter

Creating the adapter is as simple as setting the endpoint:

Define the APIs interfaces

Define the interface for each endpoint you are going to connect with. In this case we are connecting to the steams endpoint with the limit and offset parameters which are used for paging the data. These are specified in the Justin.Tv API documentation.

You will notice we are expecting back a response from the endpoint that is a List of JustinTvStreamData objects, which is the POJO we auto-generated earlier. For more information on how to define this interface see the Retrofit documentation.

Create the Twitch.Tv Service

Now that we have the endpoint established and the interface defined we need to make the Twitch.Tv service that allows making requests.

Hit the API

Making the API request is equally simple.  We just need to use the service we just created.

What is interesting here in the fact that Retrofit will download and parse the API data on a background thread, and then deliver the results back to the UI thread via the success or failure method. Retrofit also supports just downloading on whatever thread it is called on (not shown here).

Do Something Interesting With the Data

Now that the data is in a POJO do something interesting with it!
For this demo project I display the Twitch.Tv channel image and description and used the Picasso Library to download and cache the images.

TwitchClient

References

Open Source Sample Project

Interesting? 

Do you find this sort of work interesting? Do you love quaint Bucks County Pennsylvania? Are you an amazing Android Developer? Then we would love to hear from you!

23 thoughts on “Best Practices for Consuming APIs On Android”

  1. WOW! Thanks for this! Question why is your array list in a inner class?
    private static class ActivityState {
    private int nextPage = 0;

    private List streamData = new ArrayList();
    }

    1. The streamData and nextPage are both maintained inside a static inner class so that they can be saved when the device is rotated and we don’t lose our state.

      The state is saved off when returned via onRetainNonConfigurationInstance which allows saving the state of one arbitrary object which is why I wrappered all the necessary state in a static inner class. The static is also very important, if that inner class was not static it would leak the entire activity on rotation.

      In onCreate the state is restored if one is available. The adapter is populated with mState.streamData which will be the saved off data, if there was any, or an empty list on initial run.

    1. Retrofit will use the built in HTTP handling (Android/Java native clients) if OkHttp is not present. If the OkHttp library is present then it will automatically use that for all HTTP handling, which is a much more robust and performant HTTP library.

      1. You can explicitly opt-in to OkHttp by calling .setClient(new OkClient()) on the RestAdapter.Builder. But like Bill said, Retrofit will see OkHttp is available and use it automatically.

    1. I think it could be useful. Right now I typically use: http://www.parcelabler.com which has also just recently released an Android Studio plugin as well. If you are going to add Parcelable generation to jsonschema2pojo you may want to use that project as a starting point.

  2. Thanks for posting this! For some reason I thought OkHttp was integrated into Retrofit. Posts were bombing out with a network error on KitKat when using the default Android HTTP library. As soon as I included the OkHttp library everything began working flawlessly!

  3. It would be nice to have an example that actually handles a little cache with the okHttp, cause yours don’t, do you think it would be possible to update the tutorial?

  4. Hi,

    My question is, by creating Callback<List> as an anonymous inner class, aren’t you leaking the Activity? The general advice for inner classes would be that they shouldn’t outlive their parents, and this is a clear case when the Callback instance can be held in memory for a long time if the request takes too long.

    Thank you,
    Egor

    1. That is a good point and really an issue with a basic configuration of Retrofit. You really need a framework above Retrofit in order to handle this as well as prevent needless re-downloading data when for instance the phone is rotated in the middle of a download. But it is a bit complex for a basic stack post and not included here.

      I gave a full presentation on integrating Retrofit and we discussed approaches we took in order to build frameworks above Retrofit to solve this problem that you can watch here: http://wdonahue.com/blog/files/f09d0f721122a6edfd6949767f6578d4-13.html

      We talk about solutions we have used in the past at 43:46 into the video. Maybe at some point I could write and release this as an open source project.

  5. Without any doubt awsome tutorial. But when i get sample app from Git it not working , means that , may be some problem in URL because progress bar keep rolling-and-rolling. It may be possible i am doing some thing wrong . Please suggest me so that i can explore more and more. I am new born for Retrofit

Leave a Reply

Your email address will not be published. Required fields are marked *