Sunday, June 26, 2011

Simple RSS Reader in Android


The Connexions app reads both Atom and RSS feeds. The implementations are similar, but the Atom reader is a bit Connexions specific because of the way we add metadata in the content element of the feed. Our RSS feeds are pretty straightforward, so the reader is also. RSS is currently used for Recently Published Content. The reader is basically a Sax parser that is looking for specific elements and grabbing the attribute or text from the needed elements.

To be a Sax parser, the RssHandler class implements the basic Sax methods of startElement(), endElement() and characters(). The 3 elements I needed from the feed were item, title and link. I set a boolean when I encounter one of the elements in startElement(). I also create a Content object when an item element is found. The Content object will be used in the other methods as well.

public void startElement(String uri, String name, String qName, Attributes atts)
{
if(name.trim().equals("item"))
{
currentContent = new Content();
}
if (name.trim().equals("title"))
{
inTitle = true;
}
else if (name.trim().equals("link"))
{
inLink = true;
}
}


In characters(), I get the text of the elements if one of the booleans have been set. Since there is no guarantee that the entire buffer will be delivered, there is code to concatenate the remaining text to the initial String is necessary. There is also code to hack the cnx.org domain sent with the feed to be mobile.cnx.org.

public void characters(char ch[], int start, int length)
{

String chars = (new String(ch).substring(start, start + length));

if (inTitle && currentContent != null)
{
if(currentContent.title == null || currentContent.title.equals("") )
{
currentContent.title = chars;currentContent.title = chars;
}
else
{
currentContent.title = currentContent.title + chars;
}
}
else if(inLink && currentContent != null)
{
String link = new String(chars);
try
{
currentContent.setUrl(new URL("http://mobile.cnx.org" + link.substring(14)));
}
catch (MalformedURLException e)
{
e.printStackTrace();
}

}
}


The method endElement() resets the booleans to false, calls a method to set the correct icon on the Content object and adds the Content object to an ArrayList.

public void endElement(String uri, String name, String qName) throws SAXException
{
inTitle = false;
inLink = false;

if(currentContent != null && currentContent.url != null && currentContent.title != null && !contentList.contains(currentContent))
{
if(currentContent.getIconImage() == null)
{
setIcon();
}
contentList.add(currentContent);
}

}


The 3 methods described above are triggered by the parseFeed() method.

public ArrayList parseFeed(Context ctx, Feed feed)
{
try
{

SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
xr.setContentHandler(this);
xr.parse(new InputSource(feed.url.openStream()));

}
catch (IOException e)
{
Log.e(HANDLER, e.toString());
}
catch (SAXException e)
{
Log.e(HANDLER, e.toString());
}
catch (ParserConfigurationException e)
{
Log.e(HANDLER, e.toString());
}
return contentList;
}


You can browse the source or download a zip file of the source. Connexions for Android is available in the Android Market or from the Connexions website.

No comments:

Post a Comment