uk.org.rivernile.edinburghbustracker.android.twitter.TwitterUpdatesLoader.java Source code

Java tutorial

Introduction

Here is the source code for uk.org.rivernile.edinburghbustracker.android.twitter.TwitterUpdatesLoader.java

Source

/*
 * Copyright (C) 2012 - 2013 Niall 'Rivernile' Scott
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors or contributors be held liable for
 * any damages arising from the use of this software.
 *
 * The aforementioned copyright holder(s) hereby grant you a
 * non-transferrable right to use this software for any purpose (including
 * commercial applications), and to modify it and redistribute it, subject to
 * the following conditions:
 *
 *  1. This notice may not be removed or altered from any file it appears in.
 *
 *  2. Any modifications made to this software, except those defined in
 *     clause 3 of this agreement, must be released under this license, and
 *     the source code of any modifications must be made available on a
 *     publically accessible (and locateable) website, or sent to the
 *     original author of this software.
 *
 *  3. Software modifications that do not alter the functionality of the
 *     software but are simply adaptations to a specific environment are
 *     exempt from clause 2.
 */

package uk.org.rivernile.edinburghbustracker.android.twitter;

import android.content.Context;
import android.text.Html;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Random;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import uk.org.rivernile.android.utils.SimpleResultLoader;
import uk.org.rivernile.edinburghbustracker.android.ApiKey;

/**
 * This Loader handles fetching data from Twitter to display as news items
 * inside the application. This Loader does not expect any arguments.
 * 
 * @author Niall Scott
 * @see SimpleResultLoader
 */
public class TwitterUpdatesLoader extends SimpleResultLoader<TwitterLoaderResult> {

    /** Error code for when no data is available. */
    public static final byte ERROR_NODATA = 0;
    /** Error code for when there was a problem parsing the incoming data. */
    public static final byte ERROR_PARSEERR = 1;
    /** Error code for an IO error, such as a socket error or reading error. */
    public static final byte ERROR_IOERR = 2;
    /** There was a problem parsing the URL. Should never happen. */
    public static final byte ERROR_URLERR = 3;
    /**
     * Error code for when the URL the client thought it was requesting data
     * from differs from the URL it is receiving data from.
     */
    public static final byte ERROR_URLMISMATCH = 4;

    private static final String REQUEST_URL = "http://edinb.us/api/" + "TwitterStatuses?appName=MBE&key=";

    private static final Random random = new Random(System.currentTimeMillis());

    /**
     * Create a new TwitterUpdatesLoader.
     * 
     * @param context A Context object.
     */
    public TwitterUpdatesLoader(final Context context) {
        super(context);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public TwitterLoaderResult loadInBackground() {
        final ArrayList<TwitterNewsItem> items = new ArrayList<TwitterNewsItem>();

        final StringBuilder urlBuilder = new StringBuilder(REQUEST_URL);
        urlBuilder.append(ApiKey.getHashedKey());
        urlBuilder.append("&random=").append(random.nextInt());

        byte error;

        try {
            // Create URL object.
            final URL u = new URL(urlBuilder.toString());
            // Open the connection to the HTTP server.
            final HttpURLConnection con = (HttpURLConnection) u.openConnection();
            // Buffer the input.
            final BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));

            // Check to see if the URL we've connected to is what we expected.
            if (u.getHost().equals(con.getURL().getHost())) {
                // All text will be put in to a StringBuilder.
                final StringBuilder sb = new StringBuilder();
                String lineIn;

                // Keep accepting input until there is no more.
                while ((lineIn = in.readLine()) != null) {
                    sb.append(lineIn);
                }

                // Parse the JSON.
                error = parseJSON(items, sb.toString());
            } else {
                error = ERROR_URLMISMATCH;
            }

            // Remember to release resources.
            in.close();
            con.disconnect();
        } catch (MalformedURLException e) {
            error = ERROR_URLERR;
        } catch (IOException e) {
            error = ERROR_IOERR;
        } catch (JSONException e) {
            error = ERROR_PARSEERR;
        }

        // Error codes are >= 0, so if the error code matches this, create an
        // error object, otherwise create a result object.
        if (error < 0) {
            return new TwitterLoaderResult(items);
        } else {
            return new TwitterLoaderResult(error);
        }
    }

    /**
     * Parse the JSON which was received from Twitter.
     * 
     * @param items The ArrayList to put all TwitterNewsItems in to.
     * @param jsonString The source JSON String.
     * @throws JSONException If a parsing error occurs.
     */
    private byte parseJSON(final ArrayList<TwitterNewsItem> items, final String jsonString) throws JSONException {
        // Make sure that the JSON String exists.
        if (jsonString == null || jsonString.length() == 0) {
            return ERROR_NODATA;
        }

        // Twitter starts off as a JSON Array.
        final JSONArray ja = new JSONArray(jsonString);
        // Get the number of items.
        final int len = ja.length();
        JSONObject joTweet, joUser;

        for (int i = 0; i < len; i++) {
            // Get the tweet object.
            joTweet = ja.getJSONObject(i);
            // Get the user object.
            joUser = joTweet.getJSONObject("user");

            // Create the TwitterNewsItem and add to the ArrayList.
            items.add(new TwitterNewsItem(Html.fromHtml(joTweet.getString("text")).toString(),
                    joUser.getString("name"), joTweet.getString("created_at")));
        }

        return -1;
    }
}