com.sonaive.v2ex.ui.debug.RSSPullService.java Source code

Java tutorial

Introduction

Here is the source code for com.sonaive.v2ex.ui.debug.RSSPullService.java

Source

/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.sonaive.v2ex.ui.debug;

import android.app.IntentService;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;

import com.sonaive.v2ex.provider.V2exContract;
import com.sonaive.v2ex.provider.V2exContract.*;

import org.apache.http.HttpStatus;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Date;
import java.util.Vector;

/**
 * This service pulls RSS content from a web site URL contained in the incoming Intent (see
 * onHandleIntent()). As it runs, it broadcasts its status using LocalBroadcastManager; any
 * component that wants to see the status should implement a subclass of BroadcastReceiver and
 * register to receive broadcast Intents with category = CATEGORY_DEFAULT and action
 * Constants.BROADCAST_ACTION.
 *
 */
public class RSSPullService extends IntentService {
    // Used to write to the system log from this class.
    public static final String LOG_TAG = "RSSPullService";

    // Defines and instantiates an object for handling status updates.

    /**
     * An IntentService must always have a constructor that calls the super constructor. The
     * string supplied to the super constructor is used to give a name to the IntentService's
     * background thread.
     */
    public RSSPullService() {

        super("RSSPullService");
    }

    /**
     * In an IntentService, onHandleIntent is run on a background thread.  As it
     * runs, it broadcasts its current status using the LocalBroadcastManager.
     * @param workIntent The Intent that starts the IntentService. This Intent contains the
     * URL of the web site from which the RSS parser gets data.
     */
    @Override
    protected void onHandleIntent(Intent workIntent) {

        BroadcastNotifier mBroadcaster = new BroadcastNotifier(this);
        // Gets a URL to read from the incoming Intent's "data" value
        String localUrlString = workIntent.getDataString();

        // Creates a projection to use in querying the modification date table in the provider.
        final String[] dateProjection = new String[] { ModiDates._ID, ModiDates.MODI_DATE };

        // A URL that's local to this method
        URL localURL;

        // A cursor that's local to this method.
        Cursor cursor = null;

        /*
         * A block that tries to connect to the Picasa featured picture URL passed as the "data"
         * value in the incoming Intent. The block throws exceptions (see the end of the block).
         */
        try {

            // Convert the incoming data string to a URL.
            localURL = new URL(localUrlString);

            /*
             * Tries to open a connection to the URL. If an IO error occurs, this throws an
             * IOException
             */
            URLConnection localURLConnection = localURL.openConnection();

            // If the connection is an HTTP connection, continue
            if ((localURLConnection instanceof HttpURLConnection)) {

                // Broadcasts an Intent indicating that processing has started.
                mBroadcaster.broadcastIntentWithState(Constants.STATE_ACTION_STARTED);

                // Casts the connection to a HTTP connection
                HttpURLConnection localHttpURLConnection = (HttpURLConnection) localURLConnection;

                // Sets the user agent for this request.
                localHttpURLConnection.setRequestProperty("User-Agent", Constants.USER_AGENT);

                /*
                 * Queries the content provider to see if this URL was read previously, and when.
                 * The content provider throws an exception if the URI is invalid.
                 */
                cursor = getContentResolver().query(ModiDates.CONTENT_URI, dateProjection, null, null, null);

                // Flag to indicate that new metadata was retrieved
                boolean newMetadataRetrieved;

                /*
                 * Tests to see if the table contains a modification date for the URL
                 */
                if (null != cursor && cursor.moveToFirst()) {

                    long storedModifiedDate = cursor.getLong(cursor.getColumnIndex(ModiDates.MODI_DATE));

                    /*
                     * If the modified date isn't 0, sets another request property to ensure that
                     * data is only downloaded if it has changed since the last recorded
                     * modification date. Formats the date according to the RFC1123 format.
                     */
                    if (0 != storedModifiedDate) {
                        localHttpURLConnection.setRequestProperty("If-Modified-Since",
                                org.apache.http.impl.cookie.DateUtils.formatDate(new Date(storedModifiedDate),
                                        org.apache.http.impl.cookie.DateUtils.PATTERN_RFC1123));
                    }

                    // Marks that new metadata does not need to be retrieved
                    newMetadataRetrieved = false;

                } else {

                    /*
                     * No modification date was found for the URL, so newmetadata has to be
                     * retrieved.
                     */
                    newMetadataRetrieved = true;

                }

                // Reports that the service is about to connect to the RSS feed
                mBroadcaster.broadcastIntentWithState(Constants.STATE_ACTION_CONNECTING);

                // Gets a response code from the RSS server
                int responseCode = localHttpURLConnection.getResponseCode();

                switch (responseCode) {

                // If the response is OK
                case HttpStatus.SC_OK:

                    // Gets the last modified data for the URL
                    long lastModifiedDate = localHttpURLConnection.getLastModified();

                    // Reports that the service is parsing
                    mBroadcaster.broadcastIntentWithState(Constants.STATE_ACTION_PARSING);

                    /*
                     * Instantiates a pull parser and uses it to parse XML from the RSS feed.
                     * The mBroadcaster argument send a broadcaster utility object to the
                     * parser.
                     */
                    RSSPullParser localPicasaPullParser = new RSSPullParser();

                    localPicasaPullParser.parseXml(localURLConnection.getInputStream(), mBroadcaster);

                    // Reports that the service is now writing data to the content provider.
                    mBroadcaster.broadcastIntentWithState(Constants.STATE_ACTION_WRITING);

                    // Gets image data from the parser
                    Vector<ContentValues> imageValues = localPicasaPullParser.getImages();

                    // Stores the number of images
                    int imageVectorSize = imageValues.size();

                    // Creates one ContentValues for each image
                    ContentValues[] imageValuesArray = new ContentValues[imageVectorSize];

                    imageValuesArray = imageValues.toArray(imageValuesArray);

                    /*
                     * Stores the image data in the content provider. The content provider
                     * throws an exception if the URI is invalid.
                     */
                    getContentResolver().bulkInsert(PicasaImages.CONTENT_URI, imageValuesArray);

                    // Creates another ContentValues for storing date information
                    ContentValues dateValues = new ContentValues();

                    // Adds the URL's last modified date to the ContentValues
                    dateValues.put(ModiDates.MODI_DATE, lastModifiedDate);

                    if (newMetadataRetrieved) {

                        // No previous metadata existed, so insert the data
                        getContentResolver().insert(ModiDates.CONTENT_URI, dateValues);
                    } else {

                        // Previous metadata existed, so update it.
                        getContentResolver().update(ModiDates.CONTENT_URI, dateValues,
                                ModiDates._ID + "=" + cursor.getString(cursor.getColumnIndex(ModiDates._ID)), null);
                    }
                    break;

                }

                // Reports that the feed retrieval is complete.
                mBroadcaster.broadcastIntentWithState(Constants.STATE_ACTION_COMPLETE);
            }

            // Handles possible exceptions
        } catch (MalformedURLException localMalformedURLException) {

            localMalformedURLException.printStackTrace();

        } catch (IOException localIOException) {

            localIOException.printStackTrace();

        } catch (XmlPullParserException localXmlPullParserException) {

            localXmlPullParserException.printStackTrace();

        } finally {

            // If an exception occurred, close the cursor to prevent memory leaks.
            if (null != cursor) {
                cursor.close();
            }
        }
    }

}