How to write Android ATOM parser application

In this post we are going to show you our Android Atom Parser application and how it was build. Our application connects to the Atom feed (http://www.itcuties.com/feed/atom) of our blog itcuties.com and displays a list of posts published. When an item is tapped post details are displayed in the application. Our application looks like this.

ITCuties Android Atom parser - All posts screen

ITCuties Android Atom parser – All posts screen

ITCuties Android Atom parser - Post details screen

ITCuties Android Atom parser – Post details screen

Here is our project structure.

ITCuties Android Atom parser - Eclipse project structure

ITCuties Android Atom parser – Eclipse project structure

Here are the codes.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.itcuties.android.apps.itcatomreaderapp"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.itcuties.android.apps.itcatomreaderapp.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.itcuties.android.apps.itcatomreaderapp.DetailsActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
            </intent-filter>
        </activity>
    </application>

</manifest>

This application descriptor contains information about activities used by our application which are – MainActivity used to display channel elements list and DetailsActivity used to display channel element details.android.permission.INTERNET permission is added to the descriptor so that our application can use Internet connection.

activity_main.xml

ITCuties Android Atom parser - Channel items layout

ITCuties Android Atom parser – Channel items layout

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

   	<ListView
        android:id="@+id/listMainView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >
    </ListView>

</RelativeLayout>

This is the layout which is used to display a list of all Atom feed elements. Simple ListView component is used to achieve that.

activity_details.xml

ITCuties Android Atom parser - Details layout

ITCuties Android Atom parser – Details layout

<?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" >

    <TextView
        android:id="@+id/detailsTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="[POST TITLE GOES HERE]"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <WebView
        android:id="@+id/detailsWebView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

This is the layout that we are using to display Atom feed element details. TextView component is used to display element title (post title). WebView component is used to display post details – our Atom feed gives you HTML formatted element contents, we display it the same way as we displayed local HTML data in our earlier tutorial How to open a webpage or a HTML fragment in your application

MainActivity.java

package com.itcuties.android.apps.itcatomreaderapp;

import java.util.List;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import com.itcuties.android.apps.itcatomreaderapp.data.RssAtomItem;
import com.itcuties.android.apps.itcatomreaderapp.listeners.ListListener;
import com.itcuties.android.apps.itcatomreaderapp.util.RssAtomReader;

/**
 * Main activity displaying a list of ATOM items
 * 
 * @author itcuties
 *
 */
public class MainActivity extends Activity {

	 // A reference to the local object
    private MainActivity local;
     
    /**
     * This method creates main application view
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Set view
        setContentView(R.layout.activity_main);
 
        // Set reference to this activity
        local = this;
         
        GetRSSDataTask task = new GetRSSDataTask();
         
        // Start download RSS task
        task.execute("http://www.itcuties.com/feed/atom");
       
    }
     
    private class GetRSSDataTask extends AsyncTask<String, Void, List<RssAtomItem> > {
        @Override
        protected List<RssAtomItem> doInBackground(String... urls) {
             
            try {
                // Create RSS reader
                RssAtomReader rssReader = new RssAtomReader(urls[0]);
             
                // Parse RSS, get items
                return rssReader.getItems();
             
            } catch (Exception e) {
                Log.e("ITCRssAtomReader", e.getMessage());
            }
             
            return null;
        }
         
        @Override
        protected void onPostExecute(List<RssAtomItem> result) {
             
            // Get a ListView from main view
            ListView itcItems = (ListView) findViewById(R.id.listMainView);
                         
            // Create a list adapter
            ArrayAdapter<RssAtomItem> adapter = new ArrayAdapter<RssAtomItem>(local,android.R.layout.simple_list_item_1, result);
            // Set list adapter for the ListView
            itcItems.setAdapter(adapter);
                         
            // Set list view item click listener
            itcItems.setOnItemClickListener(new ListListener(result, local));
        }
    }

}

In this acitivity we start a task in the onCreate method. This task is implemented as a private GetRSSDataTask class which extends AsyncTask class. Task downloads Atom feed data in the doInBackground method. After download is done the doPostExecute method is called automatically, where an ArrayAdapter is created and connected to the ListView component present in activity_main layout of the application. Here also we set a ListListener object as a ListView‘s onItemClickListener.

ListListener.java

package com.itcuties.android.apps.itcatomreaderapp.listeners;

import java.util.List;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;

import com.itcuties.android.apps.itcatomreaderapp.DetailsActivity;
import com.itcuties.android.apps.itcatomreaderapp.data.RssAtomItem;

/**
 * Class implements a list listener
 * 
 * @author itcuties
 *
 */
public class ListListener implements OnItemClickListener {

	// List item's reference
	List<RssAtomItem> listItems;
	// Calling activity reference
	Activity activity;
	
	public ListListener(List<RssAtomItem> aListItems, Activity anActivity) {
		listItems = aListItems;
		activity  = anActivity;
	}
	
	public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
		Intent i = new Intent(activity, DetailsActivity.class);
		i.setData(Uri.parse(listItems.get(pos).getContent()));
		
		i.putExtra("title", listItems.get(pos).getTitle());
		i.putExtra("content", listItems.get(pos).getContent());
		
		activity.startActivity(i);
		
	}
}

This is our implementation of OnItemClickListener class. When an item is clicked the onItemClick method is called which starts the DetailsActivity. We put Atom feed element’s title and contents to be read by the activity started activity. To learn more on how to exchange data between activities see our other tutorial – How to exchange data between Activities in Android – Intent putExtra method.

DetailsActivity.java

package com.itcuties.android.apps.itcatomreaderapp;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebView;
import android.widget.TextView;

/**
 * An activity displaying a ATOM entity details - the post
 * 
 * @author itcuties
 *
 */
public class DetailsActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_details);
		
		String title 	= (String)getIntent().getExtras().get("title");
		String content 	= (String)getIntent().getExtras().get("content");
		

		Log.d("DEBUG", "title:\t" + title);

		Log.d("DEBUG", "content:\t\t" + content);
		
		
		TextView titleTV = (TextView)findViewById(R.id.detailsTextView);
		WebView webView	 = (WebView)findViewById(R.id.detailsWebView);
		
		titleTV.setText(title);
		webView.loadData(content, "text/html", "UTF-8");
		
	}	
}

This activity reads title and contents data and displays it in the activity_details layout using WebView component defined there.

RssAtomItem.java

package com.itcuties.android.apps.itcatomreaderapp.data;

/**
 * This class represents an ATOM entity - a post
 * 
 * @author itcuties
 *
 */
public class RssAtomItem {
	
	private String title;
	
	private String content;

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	@Override
	public String toString() {
		return title;
	}

}

This class represents Atom entity which is the element of the feed.

RssAtomReader.java

package com.itcuties.android.apps.itcatomreaderapp.util;

import java.util.List;

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

import com.itcuties.android.apps.itcatomreaderapp.data.RssAtomItem;

/**
 * Class reads RSS data.
 * 
 * @author ITCuties
 *
 */
public class RssAtomReader {
	
	private String rssUrl;

	/**
	 * Constructor
	 * 
	 * @param rssUrl
	 */
	public RssAtomReader(String rssUrl) {
		this.rssUrl = rssUrl;
	}

	/**
	 * Get RSS items.
	 * 
	 * @return
	 */
	public List<RssAtomItem> getItems() throws Exception {
		// SAX parse RSS data
		SAXParserFactory factory = SAXParserFactory.newInstance();
		
		SAXParser saxParser = factory.newSAXParser();

		RssAtomParseHandler handler = new RssAtomParseHandler();
		
		saxParser.parse(rssUrl, handler);
		
		return handler.getItems();
		
	}

}

This is the class that initiates parsing of the Atom feed data. In the getItems method a SAXParser is created using the SAXParserFactory instance. Next our custom RssAtomParseHandler is created which is then used to parse Atom feed and return the results.

RssAtomParseHandler.java

package com.itcuties.android.apps.itcatomreaderapp.util;

import java.util.ArrayList;
import java.util.List;

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

import com.itcuties.android.apps.itcatomreaderapp.data.RssAtomItem;

/**
 * SAX tag handler
 * 
 * @author ITCuties
 *
 */
public class RssAtomParseHandler extends DefaultHandler {

	private List<RssAtomItem> rssItems;
	
	// Used to reference item while parsing
	private RssAtomItem currentItem;
	
	// Parsing title indicator
	private boolean parsingTitle;
	// Parsing link indicator
	private boolean parsingContents;
	// A buffer for title contents
	private StringBuffer currentTitleSb;
	// A buffer for content tag contents
	private StringBuffer currentContentSb;
	
	public RssAtomParseHandler() {
		rssItems = new ArrayList<RssAtomItem>();
	}
	
	public List<RssAtomItem> getItems() {
		return rssItems;
	}
	
	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		
		if ("entry".equals(qName)) {
			currentItem = new RssAtomItem();
		} else if ("title".equals(qName)) {
			parsingTitle = true;
			currentTitleSb = new StringBuffer();
		} else if ("content".equals(qName)) {
			parsingContents = true;
			currentContentSb = new StringBuffer();
		}
	}
	
	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		
		if ("entry".equals(qName)) {
			rssItems.add(currentItem);
			currentItem = null;
		} else if ("title".equals(qName)) {
			parsingTitle = false;
			
			if (currentItem != null) // There is a title tag for a whole channel present. It is being parsed before the entry tag is present, so we need to check if item is not null
				currentItem.setTitle(currentTitleSb.toString());
			
		} else if ("content".equals(qName)) {
			parsingContents = false;
			
			if (currentItem != null)
				currentItem.setContent(currentContentSb.toString());
			
		}
	}
	
	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		
		if (parsingTitle) {
			if (currentItem != null)
				currentTitleSb.append(new String(ch, start, length));
		} else if (parsingContents) {
			if (currentItem != null)
				currentContentSb.append(new String(ch, start, length));
		}
	}
	
}

This is the heart of our application. This code is responsible for parsing plain XML Atom feed data. This class extends DefaultHandler class. During the parsing process a List of RssAtomItem objects is created. XML tags being parsed are:
entry – this tag contains information about Atom feed element – a post,
title – this tag contains information about Atom feed element title – post title,
content – this tag contains Atom feed element content – post body.

In this tutorial we have used knowledge from our previous tutorials:
How to write Android RSS parser
Android AsyncTask RSS Reader
Android RSS Reader – Multicategory reader, Tab Layout example
How to exchange data between Activities in Android – Intent putExtra method
How to open a webpage or a HTML fragment in your application

Download this sample code here.

Install this application from here.

This code is available on our GitHub repository as well.

16 Responses to "How to write Android ATOM parser application"

  1. drago says:

    I need to load an xml atom file but it is on my res folder in my application (on local), how I can make this?

    Reply
  2. Asim ibn Thabit says:

    Hello ITCUTIES, Thanks for tutorial.

    Please can you help me, everything are OK but not displayed characters “ë” in APP.

    How to fix this problem…

    Reply
  3. Deval says:

    Hello ITCuties,i want to parse this site http://sports.teilar.gr/?feed=rss2
    With the above code,when i run your atom feed its ok,but when i run my site i get a white screen.Can you please help me?

    Reply
  4. Tyler Holmgren says:

    I am having an issue with the atom feed I am trying to parse. It displays things that should have been parsed like ” as " as well as a few others. Is there an easy way to fix this?

    Reply
  5. Nonsense says:

    I have getting crashed to desktop when testing on Emulator with parse from google alerts site (https://www.google.com/alerts)

    Error Message on Logcat:
    10-12 07:08:23.825: E/AndroidRuntime(1757): FATAL EXCEPTION: main
    10-12 07:08:23.825: E/AndroidRuntime(1757): Process: com.itcuties.android.apps.itcatomreaderapp, PID: 1757
    10-12 07:08:23.825: E/AndroidRuntime(1757): java.lang.NullPointerException
    10-12 07:08:23.825: E/AndroidRuntime(1757): at android.widget.ArrayAdapter.getCount(ArrayAdapter.java:330)
    10-12 07:08:23.825: E/AndroidRuntime(1757): at android.widget.ListView.setAdapter(ListView.java:480)
    10-12 07:08:23.825: E/AndroidRuntime(1757): at com.itcuties.android.apps.itcatomreaderapp.MainActivity$GetRSSDataTask.onPostExecute(MainActivity.java:73)
    10-12 07:08:23.825: E/AndroidRuntime(1757): at com.itcuties.android.apps.itcatomreaderapp.MainActivity$GetRSSDataTask.onPostExecute(MainActivity.java:1)
    10-12 07:08:23.825: E/AndroidRuntime(1757): at android.os.AsyncTask.finish(AsyncTask.java:632)
    10-12 07:08:23.825: E/AndroidRuntime(1757): at android.os.AsyncTask.access$600(AsyncTask.java:177)
    10-12 07:08:23.825: E/AndroidRuntime(1757): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
    10-12 07:08:23.825: E/AndroidRuntime(1757): at android.os.Handler.dispatchMessage(Handler.java:102)
    10-12 07:08:23.825: E/AndroidRuntime(1757): at android.os.Looper.loop(Looper.java:136)
    10-12 07:08:23.825: E/AndroidRuntime(1757): at android.app.ActivityThread.main(ActivityThread.java:5017)
    10-12 07:08:23.825: E/AndroidRuntime(1757): at java.lang.reflect.Method.invokeNative(Native Method)
    10-12 07:08:23.825: E/AndroidRuntime(1757): at java.lang.reflect.Method.invoke(Method.java:515)
    10-12 07:08:23.825: E/AndroidRuntime(1757): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
    10-12 07:08:23.825: E/AndroidRuntime(1757): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
    10-12 07:08:23.825: E/AndroidRuntime(1757): at dalvik.system.NativeStart.main(Native Method)
    10-12 07:08:24.155: W/ActivityManager(1272): Force finishing activity com.itcuties.android.apps.itcatomreaderapp/.MainActivity

    How I can fix it?

    Reply
  6. Åke Äö says:

    This not print scandinavians letters (ÅåÄäÖö) correct :(
    How I fix it?
    Thanks :)

    Reply
  7. Tasbeeh says:

    Hi
    Thanx for the code , it worked perfectly but when I change the Url in this Line : task.execute(“http://www.itcuties.com/feed/atom”)

    it becomes too Slow and shows me only a White page.

    Please Help Me

    Reply
  8. Wilfried says:

    Thanx you very much,this tutorial help me .
    But i have a problem,i can not see total content of the description in my rss feed.
    I don’t know where is the problem.
    Please help me

    public class RssParseHandler extends DefaultHandler {
    
    	private List RSSItems;
    
    	// Used to reference item while parsing
    	private RSSItem currentItem;
    
    	private boolean parsingTitle;
    
    	private boolean parsingDescription;
    
    	private boolean parsingDate;
    
    	private boolean parsingImage;
    
    	private boolean parsingLink;
    
    	public RssParseHandler() {
    		RSSItems = new ArrayList();
    	}
    
    	public List getItems() {
    		return RSSItems;
    	}
    
    	@Override
    	public void startElement(String uri, String localName, String qName,
    			Attributes attributes) throws SAXException {
    		if (&quot;item&quot;.equals(qName)) {
    			currentItem = new RSSItem();
    		} else if (&quot;title&quot;.equals(qName)) {
    			parsingTitle = true;
    		} else if (&quot;description&quot;.equals(qName)) {
    			parsingDescription = true;
    		} else if (&quot;pubDate&quot;.equals(qName)) {
    			parsingDate = true;
    		} else if (&quot;link&quot;.equals(qName)) {
    			parsingLink = true;
    		} else if (&quot;enclosure&quot;.equals(qName)) {
    			parsingImage = true;
    			currentItem.setImage(attributes.getValue(&quot;url&quot;));
    		}
    	}
    
    	@Override
    	public void endElement(String uri, String localName, String qName)
    			throws SAXException {
    		if (&quot;item&quot;.equals(qName)) {
    			RSSItems.add(currentItem);
    			currentItem = null;
    		} else if (&quot;title&quot;.equals(qName)) {
    			parsingTitle = false;
    		} else if (&quot;decription&quot;.equals(qName)) {
    			parsingDescription = false;
    		} else if (&quot;pubDate&quot;.equals(qName)) {
    			parsingDate = false;
    		} else if (&quot;link&quot;.equals(qName)) {
    			parsingLink = false;
    		} else if (&quot;image&quot;.equals(qName)) {
    			parsingImage = false;
    		} else if (&quot;enclosure&quot;.equals(qName)) {
    			parsingImage = false;
    		}
    	}
    
    	@Override
    	public void characters(char[] ch, int start, int length)
    			throws SAXException {
    
    		if (parsingTitle) {
    			if (currentItem != null)
    				currentItem.setTitle(new String(ch, start, length));
    		} else if (parsingDescription) {
    			if (currentItem != null) {
    				currentItem.setDescription(new String(ch, start, length));
    				parsingDescription = false;
    			}
    		} else if (parsingDate) {
    			if (currentItem != null) {
    				String date = new String(ch, start, length);
    				currentItem.setDate(date.substring(5, date.length()).replace(
    						&quot; +0000&quot;, &quot; GMT&quot;));
    				parsingDate = false;
    			}
    		} else if (parsingLink) {
    			if (currentItem != null) {
    				currentItem.setLink(new String(ch, start, length));
    				parsingLink = false;
    			}
    		}
    	}
    
    }
    
    Reply
  9. swapnil says:

    How to convert mainactivity in fragment

    How i call itcItems.setOnItemClickListener …
    In fragment? ?

    Reply
  10. aida says:

    hello..thats very useful.but i still have a problem.i dont know why nothing can be replaced with this address u said:
    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(
    Request.Method.GET,
    “http://www.itcuties.com/feed/json”,
    how can i put another web address here?
    im very thank full to u..plz help me.

    Reply
  11. Android Developer says:

    Works like a charm, Thanks!

    Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>