Home | History | Annotate | Download | only in threadsample
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.threadsample;
     18 
     19 import org.xml.sax.helpers.DefaultHandler;
     20 import org.xmlpull.v1.XmlPullParser;
     21 import org.xmlpull.v1.XmlPullParserException;
     22 import org.xmlpull.v1.XmlPullParserFactory;
     23 
     24 import android.content.ContentValues;
     25 import android.net.Uri;
     26 
     27 import java.io.IOException;
     28 import java.io.InputStream;
     29 import java.util.Vector;
     30 
     31 /**
     32  * RSSPullParser reads an RSS feed from the Picasa featured pictures site. It uses
     33  * several packages from the widely-known XMLPull API.
     34  *
     35  */
     36 public class RSSPullParser extends DefaultHandler {
     37     // Global constants
     38 
     39     // An attribute value indicating that the element contains media content
     40     private static final String CONTENT = "media:content";
     41 
     42     // An attribute value indicating that the element contains a thumbnail
     43     private static final String THUMBNAIL = "media:thumbnail";
     44 
     45     // An attribute value indicating that the element contains an item
     46     private static final String ITEM = "item";
     47 
     48     // Sets the initial size of the vector that stores data.
     49     private static final int VECTOR_INITIAL_SIZE = 500;
     50 
     51     // Storage for a single ContentValues for image data
     52     private static ContentValues mImage;
     53 
     54     // A vector that will contain all of the images
     55     private Vector<ContentValues> mImages;
     56 
     57     /**
     58      * A getter that returns the image data Vector
     59      * @return A Vector containing all of the image data retrieved by the parser
     60      */
     61     public Vector<ContentValues> getImages() {
     62         return mImages;
     63     }
     64     /**
     65      * This method parses XML in an input stream and stores parts of the data in memory
     66      *
     67      * @param inputStream a stream of data containing XML elements, usually a RSS feed
     68      * @param progressNotifier a helper class for sending status and logs
     69      * @throws XmlPullParserException defined by XMLPullParser; thrown if the thread is cancelled.
     70      * @throws IOException thrown if an IO error occurs during parsing
     71      */
     72     public void parseXml(InputStream inputStream,
     73             BroadcastNotifier progressNotifier)
     74             throws XmlPullParserException, IOException {
     75 
     76         // Instantiates a parser factory
     77         XmlPullParserFactory localXmlPullParserFactory = XmlPullParserFactory
     78                 .newInstance();
     79 
     80         // Turns off namespace handling for the XML input
     81         localXmlPullParserFactory.setNamespaceAware(false);
     82 
     83         // Instantiates a new pull parser
     84         XmlPullParser localXmlPullParser = localXmlPullParserFactory
     85                 .newPullParser();
     86 
     87         // Sets the parser's input stream
     88         localXmlPullParser.setInput(inputStream, null);
     89 
     90         // Gets the first event in the input sream
     91         int eventType = localXmlPullParser.getEventType();
     92 
     93         // Sets the number of images read to 1
     94         int imageCount = 1;
     95 
     96         // Returns if the current event (state) is not START_DOCUMENT
     97         if (eventType != XmlPullParser.START_DOCUMENT) {
     98 
     99             throw new XmlPullParserException("Invalid RSS");
    100 
    101         }
    102 
    103         // Creates a new store for image URL data
    104         mImages = new Vector<ContentValues>(VECTOR_INITIAL_SIZE);
    105 
    106         // Loops indefinitely. The exit occurs if there are no more URLs to process
    107         while (true) {
    108 
    109             // Gets the next event in the input stream
    110             int nextEvent = localXmlPullParser.next();
    111 
    112             // If the current thread is interrupted, throws an exception and returns
    113             if (Thread.currentThread().isInterrupted()) {
    114 
    115                 throw new XmlPullParserException("Cancelled");
    116 
    117             // At the end of the feed, exits the loop
    118             } else if (nextEvent == XmlPullParser.END_DOCUMENT) {
    119                 break;
    120 
    121             // At the beginning of the feed, skips the event and continues
    122             } else if (nextEvent == XmlPullParser.START_DOCUMENT) {
    123                 continue;
    124 
    125             // At the start of a tag, gets the tag's name
    126             } else if (nextEvent == XmlPullParser.START_TAG) {
    127                 String eventName = localXmlPullParser.getName();
    128 
    129                 /*
    130                  * If this is the start of an individual item, logs it and creates a new
    131                  * ContentValues
    132                  */
    133                 if (eventName.equalsIgnoreCase(ITEM)) {
    134 
    135                     mImage = new ContentValues();
    136 
    137                 // If this isn't an item, then checks for other options
    138                 } else {
    139 
    140                     // Defines keys to store the column names
    141                     String imageUrlKey;
    142                     String imageNameKey;
    143 
    144                     // Defines a place to store the filename of a URL,
    145                     String fileName;
    146 
    147                     // If it's CONTENT
    148                     if (eventName.equalsIgnoreCase(CONTENT)) {
    149 
    150                         // Stores the image URL and image name column names as keys
    151                         imageUrlKey = DataProviderContract.IMAGE_URL_COLUMN;
    152                         imageNameKey = DataProviderContract.IMAGE_PICTURENAME_COLUMN;
    153 
    154                     // If it's a THUMBNAIL
    155                     } else if (eventName.equalsIgnoreCase(THUMBNAIL)) {
    156 
    157                         // Stores the thumbnail URL and thumbnail name column names as keys
    158                         imageUrlKey = DataProviderContract.IMAGE_THUMBURL_COLUMN;
    159                         imageNameKey = DataProviderContract.IMAGE_THUMBNAME_COLUMN;
    160 
    161                     // Otherwise it's some other event that isn't important
    162                     } else {
    163                         continue;
    164                     }
    165 
    166                     // It's not an ITEM. Gets the URL attribute from the event
    167                     String urlValue = localXmlPullParser.getAttributeValue(null, "url");
    168 
    169                     // If the value is null, exits
    170                     if (urlValue == null)
    171                         break;
    172 
    173                     // Puts the URL and the key into the ContentValues
    174                     mImage.put(imageUrlKey, urlValue);
    175 
    176                     // Gets the filename of the URL and puts it into the ContentValues
    177                     fileName = Uri.parse(urlValue).getLastPathSegment();
    178                     mImage.put(imageNameKey, fileName);
    179                 }
    180             }
    181             /*
    182              * If it's not an ITEM, and it is an END_TAG, and the current event is an ITEM, and
    183              * there is data in the current ContentValues
    184              */
    185             else if ((nextEvent == XmlPullParser.END_TAG)
    186                     && (localXmlPullParser.getName().equalsIgnoreCase(ITEM))
    187                     && (mImage != null)) {
    188 
    189                 // Adds the current ContentValues to the ContentValues storage
    190                 mImages.add(mImage);
    191 
    192                 // Logs progress
    193                 progressNotifier.notifyProgress("Parsed Image[" + imageCount + "]:"
    194                         + mImage.getAsString(DataProviderContract.IMAGE_URL_COLUMN));
    195 
    196                 // Clears out the current ContentValues
    197                 mImage = null;
    198 
    199                 // Increments the count of the number of images stored.
    200                 imageCount++;
    201             }
    202         }
    203     }
    204 }
    205