RSS feed- Android

Parsing data from an XML file is a very common goal in mobile applications. This tutorial will provide you with a hands on approach for reading XML data with a SAX parser. SAX is an abbreviation for “Simple API for XML”, and it is a very powerful tool for reading XML.

SAX Parser Pros and Cons

One of the biggest advantages that SAX parsers offer is a low memory footprint. They parse each line of XML data at a time and consequently do not need to load the entire XML document into memory prior to making the data accessible. This is a significant boost to performance, and this really becomes visible when working with large XML documents.

One of the disadvantages of using a SAX parser is that you must define an event-driven API that will respond to each element as it is received. This can become time consuming to build, but if you are willing to spend a little extra time to get it right, the outcome will be worthwhile.

 

The source of XML is "http://feed.cnblogs.com/blog/sitehome/rss"

<feed xmlns="http://www.w3.org/2005/Atom">
    <title type="text">博客园_首页</title>
    <subtitle type="text">代码改变世界</subtitle>
    <id>http://feed.cnblogs.com/blog/sitehome/rss</id>
    <updated>2012-06-18T09:27:51Z</updated>
    <generator>feed.cnblogs.com</generator>
    <link rel="alternate" type="text/html" href="http://www.cnblogs.com/"/>
    <link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/sitehome/rss"/>
    <entry>
        <id>
            http://www.cnblogs.com/wison/archive/2012/06/18/2553824.html
        </id>
        <title type="text">My SQL查询 Summary &lt;无限级分类,递归检索或删除父类下的所有子类&gt;</title>
        <summary type="text">
            一张无限级的分类表,简列主要表字段主键FID.............................
        </summary>
        <published>2012-06-18T09:16:00Z</published>
        <updated>2012-06-18T09:16:00Z</updated>
        <author>
            <name>wisonlee</name>
            <uri>http://www.cnblogs.com/wison/</uri>
        </author>
        <link rel="alternate" href="http://www.cnblogs.com/wison/archive/2012/06/18/2553824.html"/>
        <link rel="alternate" type="text/html" href="http://www.cnblogs.com/wison/archive/2012/06/18/2553824.html"/>
        <content type="html">
            一张无限级的分类表,简列主要表字段主键FID,父类ID字段FPID........
        </content>
    </entry>
</feed>

Step 1: Setting Up the Application

You will need to create a new project in Eclipse. Since we are working with XML and will be making use of the Internet for data transfer, we need to give the application permission to access the Internet. To do this you need to open the application’s manifest file and add this line of code at the bottom, just before the closing </manifest> tag:

<uses-permission android:name="android.permission.INTERNET"></uses-permission>
 

Now that the application has access to the Internet .

Modify main.xml to add a TextView to display the result.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >   
    <ListView
        android:id="@+id/android:list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="fill_horizontal" 
        >
</ListView>
</LinearLayout>

we can begin implementing the SAX parser.

Step 2: Creating Classes and UI

First, we will need to create a class which contain all the getters and setters that we need to set the data and retrieve it. Below is a  Plain Old Java Object (POJO) named Message:

public class Message implements Comparable<Message>{
    static SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
    private String title;
    private URL link;
    private String description;
    private Date date;
    
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title.trim();
    }
    // getters and setters omitted for brevity 
    public URL getLink() {
        return link;
    }
    
    public void setLink(String link) {
        try {
            this.link = new URL(link);
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description.trim();
    }

    public String getDate() {
        return FORMATTER.format(this.date);
    }

    public void setDate(String date) {
        // pad the date if necessary
        while (!date.endsWith("00")){
            date += "0";
        }
        try {
            this.date = FORMATTER.parse(date.trim());
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
    
    public Message copy(){
        Message copy = new Message();
        copy.title = title;
        copy.link = link;
        copy.description = description;
        copy.date = date;
        return copy;
    }
    
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("Title: ");
        sb.append(title);
        sb.append('\n');
        sb.append("Date: ");
        sb.append(this.getDate());
        sb.append('\n');
        sb.append("Link: ");
        sb.append(link);
        sb.append('\n');
        sb.append("Description: ");
        sb.append(description);
        return sb.toString();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((date == null) ? 0 : date.hashCode());
        result = prime * result
                + ((description == null) ? 0 : description.hashCode());
        result = prime * result + ((link == null) ? 0 : link.hashCode());
        result = prime * result + ((title == null) ? 0 : title.hashCode());
        return result;
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Message other = (Message) obj;
        if (date == null) {
            if (other.date != null)
                return false;
        } else if (!date.equals(other.date))
            return false;
        if (description == null) {
            if (other.description != null)
                return false;
        } else if (!description.equals(other.description))
            return false;
        if (link == null) {
            if (other.link != null)
                return false;
        } else if (!link.equals(other.link))
            return false;
        if (title == null) {
            if (other.title != null)
                return false;
        } else if (!title.equals(other.title))
            return false;
        return true;
    }

    public int compareTo(Message another) {
        if (another == null) return 1;
        // sort descending, most recent first
        return another.date.compareTo(date);
    }
}

Step 3: The Content Handler

The content handler is where we need to handle each of the incoming events from the XML. So, basically what the content handler will do is read through the XML until it reaches the end.

When an opening tag such as <entry> is reached, the startElement handler will be called. When closing tags such as </entry> is reached, a closing method called endElement gets called. When the SAX parser reaches the closing tags, it calls a method called characters which will get all the content that is between the opening and closing tags.
We have a String that is called builder, which is set to null. Each time the parser goes through to start an end tag, we will set the builder string to the data in between those tags.
We have if statements to check when we reach a specific tag in order to use setters to set the data to an array list, so that we can display it later.

Below is the sample code used in the content handler: RssHandler.java 

public class RssHandler extends DefaultHandler{
    //Define variables to refer the element tags of xml file
    static final String PUB_DATE = "published";
    static final  String DESCRIPTION = "summary";
    static final  String LINK = "id";
    static final  String TITLE = "title";
    static final  String ITEM = "entry";
    private List<Message> messages;
    private Message currentMessage;
    private StringBuilder builder;
    
    public List<Message> getMessages(){
        return this.messages;
    }
    /*
     * This is called to get the tags value
     */
    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        super.characters(ch, start, length);
        builder.append(ch, start, length);
    }
    /*
     * This will be called when the tags of the XML end.
     * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
     */
    @Override
    public void endElement(String uri, String localName, String name)
            throws SAXException {
        super.endElement(uri, localName, name);

        if (this.currentMessage != null){
            if (localName.equalsIgnoreCase(TITLE)){
                currentMessage.setTitle(builder.toString());
            } else if (localName.equalsIgnoreCase(LINK)){
                currentMessage.setLink(builder.toString());
            } else if (localName.equalsIgnoreCase(DESCRIPTION)){
                currentMessage.setDescription(builder.toString());
            } else if (localName.equalsIgnoreCase(PUB_DATE)){
                currentMessage.setDate(builder.toString());
            } else if (localName.equalsIgnoreCase(ITEM)){
                messages.add(currentMessage);
            }
            builder.setLength(0);    
        }
    }

    /*
     * This will be called when beginning of the document. 
     * @see org.xml.sax.helpers.DefaultHandler#startDocument()
     */
    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
        messages = new ArrayList<Message>();
        builder = new StringBuilder();
    }

    /*
     * This will be called when the tags of the XML starts.
     */
    @Override
    public void startElement(String uri, String localName, String name,
            Attributes attributes) throws SAXException {
        super.startElement(uri, localName, name, attributes);
        if (localName.equalsIgnoreCase(ITEM)){
            this.currentMessage = new Message();
            builder.setLength(0);    
        }
    }
}

Step 4: Displaying the Retrieved Data

In the activity, we will need to create an instance of the SAX parser. We also need to create the handler for each of the XML tags. We also have the URL of the XML that we need to pass into the Handler. Here is the code used to implement this:

    public List<Message> parse() {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        try {
            URL feedUrl = new URL("http://feed.cnblogs.com/blog/sitehome/rss"); // URL of the XML
            InputStream inputStream=feedUrl.openConnection().getInputStream();
            SAXParser parser = factory.newSAXParser();
            RssHandler handler = new RssHandler();
            parser.parse(inputStream, handler);
            return handler.getMessages();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } 
    }

The final step is to display the data to an Activity:

    private void loadFeed(ParserType type){
        try{
            List<Message> messages = parse();
            List<String> titles = new ArrayList<String>(messages.size());
            for (Message msg : messages){
                titles.add(msg.getTitle());
            }
            ArrayAdapter<String> adapter = 
                new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1 ,titles);
            this.setListAdapter(adapter);
        } catch (Throwable t){
            Log.e("AndroidNews",t.getMessage(),t);
        }
    }

Conclusion

Now that everything is set up properly, you can run your app. The results should look like the image below. 

 

posted @ 2012-06-19 15:00  Johnny Yan  阅读(479)  评论(0)    收藏  举报