Mobile Zone is brought to you in partnership with:

Troy Miles is a Southern California based software developer. He began by writing games for the Apple II, C64 and IBM PC in assembly language over 30 years ago. After burning out on games he switch to creating windows application software in C and C++. And now he develops applications for both web, mobile web and mobile devices in C#, Objective C, Java, and JavaScript. He is also a big fan of jQuery, jQuery Mobile and PhoneGap. Troy is a DZone MVB and is not an employee of DZone and has posted 23 posts at DZone. You can read more from them at their website. View Full User Profile

Android Twitter API 1.1 Tutorial: Grabbing a User's Timeline

10.14.2013
| 15924 views |
  • submit to reddit

On 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

  1. Simply go to https://dev.twitter.com
  2. Click the "Sign in" link in the upper right hand corner
  3. Enter your credentials and click "Log in"
  4. Hover over your avatar in the upper right hand corner
  5. Click the "My applications" link
  6. Click the "Create a new application" button 
  7. Fill out the application details
  8. Accept the "Developer Rules of the Road"
  9. Complete the captcha
  10. Click the "Create your Twitter application" button
  11. On the "My applications" page, click on your application's name
  12. Your consumer key and secret will listed in the OAuth settings section


Keep your consumer key and secret secure. Don't do anything foolish with them, like publish them in a tutorial.

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

In order to get the bearer token, you need to make a post request to the Twitter token URL. With the request, you need to pass a few header keys. If each of the keys isn't correct, your request will be rejected. Also, the request body must only contain "grant_type=client_credentials", or your request will be rejected.

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

Again, please don't forget to replace the dummy consumer key and secret with your own. The code will not work without it. The project is in IntelliJ IDEA format. I just can't bring myself to use Eclipse. If you use Eclipse, simply copy the files into your project. Please feel free to use the code however you'd like.

Resources



Published at DZone with permission of Troy Miles, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)