Android Twitter API 1.1 Tutorial: Grabbing a User's Timeline
Join the DZone community and get the full member experience.
Join For FreeOn June 11, 2013, Twitter turned off version 1.0 of their REST API. The API had been deprecated for quite some time, but still a lot of people were caught by surprise. All over the Internet, a crap load of tutorials broke. Twitter was always a favorite for tutorial writers, since their servers were open and always had fresh data. Quite frankly, I was surprised how long Twitter let everyone and anyone use their servers. It was incredibly generous and must have been equally expensive.
Now the free ride isn't over. Twitter just wants to know who is using their servers. And they are using OAuth to do it. Now OAuth can be a bit tricky to work with, not overly painful, but tricky. It is also a bit of overkill if all you want to do is something as simple as grabbing a user's public timeline. Luckily, there is an easier alternative: Application-Only Authentication.
With application-only authentication, your app is able to make authenticated requests its own. It doesn't need a user's credentials. Now, it can't do everything. Since it is doesn't have a user context, it isn't able to do things like status updates. But it can do things like grabbing a user's timeline, which is what this tutorial will do.
YOU WILL NEED YOUR OWN CONSUMER KEY & SECRET!
I want to say that up
front to hopefully stop people from complaining that the app doesn't
work later. Getting a key and secret is easy and free, so there is no
good reason for not getting one. The app doesn't have a working key or
secret. It will build, but it won't run until you replace the mock key
and secret with real ones.
Getting Your Own Consumer Key and Secret
- Simply go to https://dev.twitter.com
- Click the "Sign in" link in the upper right hand corner
- Enter your credentials and click "Log in"
- Hover over your avatar in the upper right hand corner
- Click the "My applications" link
- Click the "Create a new application" button
- Fill out the application details
- Accept the "Developer Rules of the Road"
- Complete the captcha
- Click the "Create your Twitter application" button
- On the "My applications" page, click on your application's name
- Your consumer key and secret will listed in the OAuth settings section
Android's Listview Adapter and AsyncTask
This app uses a quick and simple listview to render the tweets. It looks absolutely ugly, but this tutorial is about getting access to a user's timeline in API 1.1, not how to render pretty listview in Android. There are already a lot of tutorials out there on how to that.We also make use of one of Android's cooler features, AsyncTasks. I hope that we all know by now, that we aren't suppose to do anything which takes a long time on the main UI thread, you know things like calling web services. The AsyncTask is probably the easiest way to avoid getting an ANR. And it is so dead simple to use.
// Uses an AsyncTask to download a Twitter user's timeline private class DownloadTwitterTask extends AsyncTask<String, Void, String> { final static String CONSUMER_KEY = "MY CONSUMER KEY"; final static String CONSUMER_SECRET = "MY CONSUMER SECRET"; final static String TwitterTokenURL = "https://api.twitter.com/oauth2/token"; final static String TwitterStreamURL = "https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name="; @Override protected String doInBackground(String... screenNames) { String result = null; if (screenNames.length > 0) { result = getTwitterStream(screenNames[0]); } return result; } // onPostExecute convert the JSON results into a Twitter object (which is an Array list of tweets @Override protected void onPostExecute(String result) { Twitter twits = jsonToTwitter(result); // lets write the results to the console as well for (Tweet tweet : twits) { Log.i(LOG_TAG, tweet.getText()); } // send the tweets to the adapter for rendering ArrayAdapter<Tweet> adapter = new ArrayAdapter<Tweet>(activity, android.R.layout.simple_list_item_1, twits); setListAdapter(adapter); }The app uses a private class, DownloadTwitterTask which inherits from AsyncTask. Its job is to download the current batch of tweets on the user's timeline. The doInBackground method does all of the grunt work. It grabs the user's screen name, and calls the getTwitterStream method. This is what makes the AsyncTask class cool. You don't have to think about multi-tasking or other such complexity, just what is the long running task you want to do, and do it.
Once your task is complete, return your object and AsyncTask will pass it on to the onPostExecute method, which runs on the UI thread. This is the perfect time to update your UI. Now for us, the string passed to the onPostExecute method is the user's timeline in JSON format, so we convert it to a Twitter object which we define as an array list of Tweets. We use Google's excellent Gson library to do that conversion and a few others. And finally we feed our Tweets to the list adapter for rendering.
Getting Authenticated and a User's Timeline
private String getTwitterStream(String screenName) { String results = null; // Step 1: Encode consumer key and secret try { // URL encode the consumer key and secret String urlApiKey = URLEncoder.encode(CONSUMER_KEY, "UTF-8"); String urlApiSecret = URLEncoder.encode(CONSUMER_SECRET, "UTF-8"); // Concatenate the encoded consumer key, a colon character, and the // encoded consumer secret String combined = urlApiKey + ":" + urlApiSecret; // Base64 encode the string String base64Encoded = Base64.encodeToString(combined.getBytes(), Base64.NO_WRAP); // Step 2: Obtain a bearer token HttpPost httpPost = new HttpPost(TwitterTokenURL); httpPost.setHeader("Authorization", "Basic " + base64Encoded); httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"); httpPost.setEntity(new StringEntity("grant_type=client_credentials")); String rawAuthorization = getResponseBody(httpPost); Authenticated auth = jsonToAuthenticated(rawAuthorization); // Applications should verify that the value associated with the // token_type key of the returned object is bearer if (auth != null && auth.token_type.equals("bearer")) { // Step 3: Authenticate API requests with bearer token HttpGet httpGet = new HttpGet(TwitterStreamURL + screenName); // construct a normal HTTPS request and include an Authorization // header with the value of Bearer <> httpGet.setHeader("Authorization", "Bearer " + auth.access_token); httpGet.setHeader("Content-Type", "application/json"); // update the results with the body of the response results = getResponseBody(httpGet); } } catch (UnsupportedEncodingException ex) { } catch (IllegalStateException ex1) { } return results; }We have rendered our tweets to our list view, but how did we get them? Once you have your key and secret, it is surprisingly simple to get to a user's timeline; just make a few HTTPS calls. In fact, Twitter lists out how to do it in three steps - well, OK, there are some sub-steps. The getTwitterStream method lists out all of the steps necessary to authenticate your app and then get some Tweets.
Step 1: Encode consumer key and secret
First, we need to URL
encode the consumer key and secret. Java has this function built-in,
URLEncoder, be sure to pass your encoding. Then we concatenate the
encoded strings with a semi-colon separating them and Base64 encode the
whole thing. This is the one spot where I ran into some trouble. I
wasn't sure what flag to pass. I initially tried, Base64.DEFAULT, which
didn't work. Luckily, there weren't that many options, and when I tried
Base64.NO_WRAP, it worked.
Step 2: Obtain a bearer token
If everything went well, you will now have your bearer token. Be sure to check it as well. Its token should equal "bearer".
Step 3: Authenticate API requests with bearer token
With our token, we can
now make API requests. Simply set the Authorization header equal to the
string "Bearer" plus our access token. For both the Http Post and the
Http Get, I use the same method, getResponseBody, to read the entire HTTP
stream and return it as a string. Everywhere, if we encounter an
exception, no attempt is made to recover, and we usually return an empty
string or a null.
Summary
Resources
Published at DZone with permission of Troy Miles, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments