title: Parsing Twitter API 1.1 JSON
body: <p>I've been working on an open source code of a Twitter reader (read only) (oauth 2.0) that pulls JSON from a user timeline. It successfully pulls the JSON from Twitter API 1.1. The challenge I'm facing is converting that JSON into something user friendly. I've implemented sections of another source code that focused on parsing the JSON, but I'm not very familiar with parsing JSON. It's patchwork so I know I might be overlooking something. Possibly a redundancy or missing part.</p>
  
  <p>UPDATED:
  When I run the app, it doesn't crash, it's just stuck at "Got Token!". What I'm hoping to display is a list of tweets somewhat formatted to look like one. I believe it's the MainActivity, but I could be wrong. You will need a Consumer Key and Secret to test. I'll put up what I have at the moment, but if anyone knows how I can get out of that loop, I'd appreciate your input.</p>
  
  <p>Thanks! </p>
  
  <p>MainActivity.java</p>
  
  <pre><code>package com.example.readtwitterfeed;
  
  
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.io.Reader;
  
  import org.apache.http.HttpEntity;
  import org.apache.http.HttpResponse;
  import org.apache.http.client.ClientProtocolException;
  import org.apache.http.client.methods.HttpGet;
  import org.apache.http.client.methods.HttpPost;
  import org.apache.http.entity.StringEntity;
  import org.apache.http.impl.client.DefaultHttpClient;
  import org.apache.http.params.BasicHttpParams;
  import org.json.JSONObject;
  import org.json.simple.JSONArray;
  import org.json.simple.JSONValue;
  
  import android.os.AsyncTask;
  import android.os.Bundle;
  import android.app.Activity;
  import android.util.Base64;
  import android.util.Log;
  import android.widget.TextView;
  
  import com.example.readtwitterfeed.R;
  
  public class MainActivity extends Activity {
  
  // CONSUMER API KEY - 21 characters (go here to get one: https://dev.twitter.com/apps/)
  // **** CHANGE THIS ****
  static final String twitterAPIKEY = "@@@@@@@@@@@@@@@@";
  
  // CONSUMER SECRET  - 41 characters (go here to get one: https://dev.twitter.com/apps/)
  // **** CHANGE THIS ****
  static final String twitterAPISECRET = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
  
  static final String twitterAPIurl = "https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=";
  
  // Twitter 'Screen Name'
  // **** CHANGE THIS ****
  static final String screenName = "Insert_Username_Here";
  
  // Tweets to return
  // **** CHANGE THIS, if needed ****
  static final int tweets2Return = 1;
  
  // Final URL will look like this (@ is your sreen name/return tweets):
  // https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=@@@&amp;include_rts=1&amp;count=@
  static String tweeterURL = twitterAPIurl + screenName
          + "&amp;include_rts=1&amp;count=" + tweets2Return;
  
  static String twitterToken = null;
  static String jsonTokenStream = null;
  static String jsonFeed = null;
  static String tweetJSON = null;
  
  TextView twitterText;
  
  // ////////////////////////////////////
  // onCreate - Let's get the GUI going
  // ////////////////////////////////////
  @Override
  protected void onCreate(Bundle savedInstanceState) {
  
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
  
      twitterText = (TextView) findViewById(R.id.tweetFeed);
  
      // Call first AsyncTask
      new loadTwitterToken().execute();
  }
  
  // ////////////////////////////////////////////////////////////////////
  // AsyncTask - First, let's get our Token for oAuth (from Twitter)
  // If you need oAuth help: https://dev.twitter.com/docs/auth/oauth/faq/
  // ////////////////////////////////////////////////////////////////////
  protected class loadTwitterToken extends AsyncTask&lt;Void, Void, Integer&gt; {
  
      @Override
      protected Integer doInBackground(Void... params) {
  
          //As of this writing, Twitter says, "We do not currently expire access tokens."
  
          try {
              DefaultHttpClient httpclient = new DefaultHttpClient(
                      new BasicHttpParams());
              HttpPost httppost = new HttpPost(
                      "https://api.twitter.com/oauth2/token");
  
              String apiString = twitterAPIKEY + ":" + twitterAPISECRET;
              String authorization = "Basic "
                      + Base64.encodeToString(apiString.getBytes(),
                              Base64.NO_WRAP);
  
              httppost.setHeader("Authorization", authorization);
              httppost.setHeader("Content-Type",
                      "application/x-www-form-urlencoded;charset=UTF-8");
              httppost.setEntity(new StringEntity(
                      "grant_type=client_credentials"));
  
              InputStream inputStream = null;
              // Let's send to web
              HttpResponse response = httpclient.execute(httppost);
              HttpEntity entity = response.getEntity();
              // Our response
              inputStream = entity.getContent();
              BufferedReader reader = new BufferedReader(
                      new InputStreamReader(inputStream, "UTF-8"), 8);
              StringBuilder sb = new StringBuilder();
  
              String line = null;
  
              // Will look like this:
              // {"token_type":"bearer","access_token":"AAAAAAAAAAAAAAAAAAAAABiQTgAAAAAACGie2o%2Bm7jNnxw8txVG99c1wAU8%3DmZq7qrX8JZpDFrgYyh5gLtOkJhQ7BvPD6bZ0ssitjg"}
  
              while ((line = reader.readLine()) != null) {
                  sb.append(line + "\n");
              }
  
              jsonTokenStream = sb.toString();
  
              // onPostExecute likes to get a parameter passed to work right.
              // Just passing something.
              return 1;
          } catch (Exception e) {
              Log.e("loadTwitterToken",
                      "doInBackground Error:" + e.getMessage());
              return null;
          }
      }
  
      @Override
      protected void onPostExecute(Integer result) {
  
          // Extract Token from JSON stream
          try {
              JSONObject root = new JSONObject(jsonTokenStream);
              twitterToken = root.getString("access_token");
          } catch (Exception e) {
              Log.e("loadTwitterToken", "onPost Error:" + e.getMessage());
          }
  
          twitterText.setText("Got Token!");
          // Now that we have a oAuth Token, lets get our JSON feed from twitter.
          // We call it from here to make sure the Token has been received already.
          new loadTwitterFeed().execute();
      }
  }
  
  // ///////////////////////////////////////////////////////////
  // AsyncTask - Download Twitter Feed w/Token as authorization
  // //////////////////////////////////////////////////////////
  
  protected class loadTwitterFeed extends AsyncTask&lt;Void, Void, Integer&gt; {
  
      @Override
      protected Integer doInBackground(Void... params) {
          BufferedReader reader =null;
           try{
              DefaultHttpClient httpclient = new DefaultHttpClient(
                      new BasicHttpParams());
              HttpGet httpget = new HttpGet(tweeterURL);
              httpget.setHeader("Authorization", "Bearer " + twitterToken);
              httpget.setHeader("Content-type", "application/json");
  
              InputStream inputStream = null;
              HttpResponse response = httpclient.execute(httpget);
              HttpEntity entity = response.getEntity();
  
              inputStream = entity.getContent();
              reader = new BufferedReader(
                      new InputStreamReader(inputStream, "UTF-8"), 8);
              return null;
           } catch (ClientProtocolException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          } catch (IOException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
  
      finally{
          if (reader != null)
              try {
                  reader.close();
              } catch (IOException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
      }
          return null;
  
      }
  
           protected void onPostExecute(String result) {
  
              StringBuilder sb = new StringBuilder();
              try{
              JSONObject resultObject = new JSONObject(result);
              org.json.JSONArray tweetArray = resultObject.getJSONArray("results");
              for (int t=0; t&lt;tweetArray.length(); t++) {
                  JSONObject tweetObject = tweetArray.getJSONObject(t);
                  sb.append(tweetObject.getString("from_user")+": ");
                  sb.append(tweetObject.get("text")+"\n\n");
              }
              }
              catch (Exception e) {
                  Log.e("Tweet", "Error retrieving JSON stream" + e.getMessage());
                  jsonFeed = sb.toString();
                  e.printStackTrace();
              }   
  
               }
          }
              /*String line = null;
              while ((line = reader.readLine()) != null) {
                  sb.append(line + "\n");
              }*/
  
  
  
      protected void onPostExecute(Integer result) {
          // Update GUI
          if (jsonFeed.length() &gt; 0) {
              twitterText.setText(jsonFeed);
          } else {
               //I'd assume wrong Consumer Key/Secret if this happens.
              twitterText.setText("Nothing Returned");
          }       
      }
  }
  </code></pre>
  
  <p>Activity_Main.xml</p>
  
  <pre><code>&lt;ScrollView  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical"&gt;
  
  &lt;TextView
       android:id="@+id/tweetFeed"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Loading..." /&gt;
  
  
  &lt;/ScrollView&gt;
  </code></pre>