Thursday, April 22, 2010

A simple RSS reader, using Android's org.xml.sax package.

In the last article, "Read XML Resources in Android, using XmlResourceParser: XML parsing interface", Android application read XML resource inside application. In the current article, a external XML will be read using Android SAX APIs.

The source of XML is "http://feeds.feedburner.com/Android-er?format=xml", which is RSS feed of my blog.

SAX is the Simple API for XML, originally a Java-only API. SAX was the first widely adopted API for XML in Java, and is a “de facto” standard. The current version is SAX 2.0.1, and there are versions for several programming language environments other than Java.

org.xml.sax is a Android's package provides the core SAX APIs.

In order to make it simple, only the contents under "title" tag will be retrieved and appended as a string.



To allow the Android application, "android.permission.INTERNET" have to be granted to the application. Modify AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.exercise.AndroidRssReader"
    android:versionCode="1"
    android:versionName="1.0">
  <application android:icon="@drawable/icon" android:label="@string/app_name">
      <activity android:name=".AndroidRssReader"
                android:label="@string/app_name">
          <intent-filter>
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
      </activity>

  </application>
  <uses-sdk android:minSdkVersion="4" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>


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:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  >
<TextView
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text="@string/hello" />
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:id="@+id/result" />
</ScrollView>
</LinearLayout>


Java source code.
package com.exercise.AndroidRssReader;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class AndroidRssReader extends Activity {

String streamTitle = "";

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
    
      TextView result = (TextView)findViewById(R.id.result);
    
      try {
  URL rssUrl = new URL("http://feeds.feedburner.com/Android-er?format=xml");
  SAXParserFactory mySAXParserFactory = SAXParserFactory.newInstance();
  SAXParser mySAXParser = mySAXParserFactory.newSAXParser();
  XMLReader myXMLReader = mySAXParser.getXMLReader();
  RSSHandler myRSSHandler = new RSSHandler();
  myXMLReader.setContentHandler(myRSSHandler);
  InputSource myInputSource = new InputSource(rssUrl.openStream());
  myXMLReader.parse(myInputSource);
 
  result.setText(streamTitle);
 
 } catch (MalformedURLException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
  result.setText("Cannot connect RSS!");
 } catch (ParserConfigurationException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
  result.setText("Cannot connect RSS!");
 } catch (SAXException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
  result.setText("Cannot connect RSS!");
 } catch (IOException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
  result.setText("Cannot connect RSS!");
 }
    
    
  }

  private class RSSHandler extends DefaultHandler
  {
   final int stateUnknown = 0;
   final int stateTitle = 1;
   int state = stateUnknown;
  
   int numberOfTitle = 0;
   String strTitle = "";
   String strElement = "";
  
 @Override
 public void startDocument() throws SAXException {
  // TODO Auto-generated method stub
  strTitle = "--- Start Document ---\n";
 }

 @Override
 public void endDocument() throws SAXException {
  // TODO Auto-generated method stub
  strTitle += "--- End Document ---";
  streamTitle = "Number Of Title: " + String.valueOf(numberOfTitle) + "\n"
     + strTitle;
 }

 @Override
 public void startElement(String uri, String localName, String qName,
   Attributes attributes) throws SAXException {
  // TODO Auto-generated method stub
  if (localName.equalsIgnoreCase("title"))
  {
   state = stateTitle;
   strElement = "Title: ";
   numberOfTitle++;
  }
  else
  {
   state = stateUnknown;
  }
 }

 @Override
 public void endElement(String uri, String localName, String qName)
   throws SAXException {
  // TODO Auto-generated method stub
  if (localName.equalsIgnoreCase("title"))
  {
   strTitle += strElement + "\n";
  }
  state = stateUnknown;
 }

 @Override
 public void characters(char[] ch, int start, int length)
   throws SAXException {
  // TODO Auto-generated method stub
  String strCharacters = new String(ch, start, length);
  if (state == stateTitle)
  {
   strElement += strCharacters;
  }
 }
  
  }
}


Download the files.

Further Reading: A simple RSS reader, in ListView

Update:
In current Android system, your app cannot run networking operation on main thread (or called UI thread), otherwise android.os.NetworkOnMainThreadException will be thrown. Please read the post android.os.NetworkOnMainThreadException.



17 comments:

  1. Help!! I need this in my app but it always force closes!! I can post logcat if you want... PLEASE HELP!!!

    ReplyDelete
  2. I had the same problem, but if you look at the log, you can see that there is a problem with the internet permision ...

    re-write these line in manifest ...


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

    ReplyDelete
  3. this was just to read the titles ,, can u plz tel us the code for displaying the body of the feeds also ...

    ReplyDelete
  4. thanx a lot buddy ... :) :) ..
    your blog is awesome :)

    ReplyDelete
  5. Please help. I've been wrestling with this for 3 days, but i don't understand the error. It says "the method startElement must override or implement a supertype method. How do i fix this.

    ReplyDelete
  6. I am having a problem getting your code to run.

    On line 31 of AndroidRssReader the error I am getting is "result cannot be resolved or is not a field"

    and line 10 of main.xml I get "error: Error: No resource found that matches the given name (at 'text' with value '@string/hello')."

    Any advice you can give me would be greatly appreciated.

    ReplyDelete
  7. hiiiiiiiii....
    i like ur link but i want to know how to get data one by one like new come in one edit text and other name comes in next edit text...?
    plz tell me how?

    ReplyDelete
  8. how do we add thumbnail images to it

    ReplyDelete
  9. Thanks a lot for this tutorial.
    Everything is working well...except one little thing. The text in my listView is white, i tried to change it, add a different style and change the theme but it doesn't work and i don't find where i can change it... Please help me :'(

    ReplyDelete
  10. Hello Lys Mallow,

    Are you talking about How to set textColor?

    ReplyDelete
  11. I've already try this and it did'nt works, i think it's because it's in my case in a listview and not simply a button.
    Nevertheless thank you

    ReplyDelete
  12. - Are you sure you have some text in the list, not empty?

    - I guess you have a xml (something like row.xml) to define the layout of each row in the ListView. You should change it.

    ReplyDelete
  13. Thanx a lot brooo it was fun using ur blog

    ReplyDelete
  14. Hello,

    the code works fine but everytime I run the app, it closes because of a problem with the internet. Does someone know how to fix this?

    I put uses-permission android:name="android.permission.INTERNET" in the manifest file, but it keeps closing.

    ReplyDelete
  15. hello joni,

    Is it caused by "android.os.NetworkOnMainThreadException"?

    If yes, please read android.os.NetworkOnMainThreadException.

    ReplyDelete