Making a slick RSS Reader in Android

Making a slick RSS Reader in Android


In this tutorial we will learn how to Create an RSS feed Reader in android. You will go though topics like:


Using SAXParser
Loading data from internet
AsyncTasks
Displaying a progressbar while loading data
Populating Listviews with images

Step 1: Create a New Android Project

You can create a new Android Project in the Eclipse IDE from:
File > New > New Android Project

You can use the following settings:

Project Name: RSSFeedReader
Build Target: Google APIs Platform – 2.3.3 API Level 10
Application Name: RSSFeed Reader
Package Name: com.RSSFeedReader
Create Activity: xmlparsemain
MinimumSDK: 7

Note:

RSS stands for Really Simple Sydication. It allows you to easily stay informed by retrieving the latest content from the websites you are interested in. These Feeds automatically syndicate the articles in a website and convert them into a standard XML format which can be viewed using software called RSS Feed Reader or Aggregator.

Step 2: Import the Required Resources

Include the following imports in your Main Activity (xmlparsemain),
but all the imports may not be useful, depends on how you modify your Activity.

import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
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.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;

Step 3:Adding the UI Elements

In the Main Activity we will needing a ListView to Show all the feeds in a list. Here we use a LinearLayout and create a ListView inside it. We are going to set the Background color of the ListView to white and also set the scrollingCache to false, this fixes issues with the list items changing to black.

<?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">
	<ListView android:layout_width="match_parent" android:id="@+id/listView1"
		android:layout_height="match_parent" android:scrollingCache="false"
		android:background="#ffffff" android:cacheColorHint="#00000000"></ListView>
</LinearLayout>

Step 4:The onCreate Method

rssReader-2

Now in the onCreate method we display a ProcessDialog that executes in the main thread.
Then we create an object of the loadingTask Class and call its execute method, we will be going thorough the loadingTask during the further steps.

We are also assigning an OnItemClickListener for the ListView that is going to display the feeds. Now when we click on a ListView element we use an intent to open the URL present in the element.

		lv1 = (ListView) findViewById(R.id.listView1);

		ShowProgress = ProgressDialog.show(xmlparsemain.this, "",
				"Loading. Please wait...", true);
		new loadingTask().execute("http://feeds.feedburner.com/theappleblog");

		lv1.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {

				Intent intent = new Intent(Intent.ACTION_VIEW).setData(Uri
						.parse(PostList.get(position).getUrl()));
				startActivity(intent);

			}
		});

Step 5: The Async Task (loadingTask)

Android AsyncTasks help us to implement UI threads easily and more effectively. AsyncTask is generally defined by 4 steps onPreExecute, doInBackground, onProgressUpdate and onPostExecute. Here, in this tutorial we use only doInBackground and onPostExecute steps.

Here we extend the AsyncTask class Lets call it the loadingTask class. In this class the doInBackground method handles the loading of the data from the URL and parsing it using the SAX Parser in a background thread. All the processing that is done in this method does not effect the Main UI so the application does not freeze the UI when it is downloading data from the URL.

The onPostExecute method is directly invoked on the main UI, it is automatically executed after the completion of the background thread. We can use this method to update the UI according to the result obtained in the background thread. We us this method to attach the ListView Adapter which is generated and to remove the ProgressDialog.

Note:

You can also use a Thread and a Handler to accomplish the task but i have opted for the AsyncTask as it provides a structured and organized way of running background threads.

Here, when an object of this class is created the doInBackground method is automatically executed and the parameters given to the object are passed on to this method(in this case a sting containing the feed URL is passed into the method) the first element of the string array “urls” contains the feed URL i.e (urls[0]). The SAXHelper object is created and urls[0] is sent as an argument.

	class loadingTask extends AsyncTask<String, Void, String> {

		protected String doInBackground(String... urls) {

			SAXHelper sh = null;
			try {
				sh = new SAXHelper(urls[0]);
			} catch (MalformedURLException e) {
				e.printStackTrace();
			}
			sh.parseContent("");
			return "";

		}

		protected void onPostExecute(String s) {
			lv1.setAdapter(new EfficientAdapter(xmlparsemain.this, PostList));
			ShowProgress.dismiss();

		}
	}

Step 6: The Adapter for the ListView

We make an Adapter for the ListView(EfficientAdapter) By extending the BaseAdapter class. All the unimplemented methods are added by eclipse itself. We just modify the getView method

import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class EfficientAdapter extends BaseAdapter {
	private Activity activity;
	private ArrayList<Post> data;
	private static LayoutInflater inflater = null;
	public ImageLoader imageLoader;
	ViewHolder holder;

	EfficientAdapter(Activity a, ArrayList<Post> d) {

		activity = a;
		data = d;
		inflater = (LayoutInflater) activity
				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		imageLoader = new ImageLoader(activity.getApplicationContext());

	}

	@Override
	public int getCount() {
		return data.toArray().length;

	}

	@Override
	public Object getItem(int position) {

		return position;
	}

	@Override
	public long getItemId(int position) {

		return position;
	}

	public static class ViewHolder {
		public TextView label;
		public TextView addr;
		public ImageView image;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		View vi = convertView;

		return vi;
	}

}

Step 7: The getView Method

Here we override the getView method that prepares view for items within list.

The Adapter provides the ListView with a new view everytime a new item is displayed. But even if the ListView contains many items only the views visible on the UI are created and when we scroll the List the Views which are scrolled up are again used for displaying the lower items.

The getView method returns our row with assigned string values to the text fields defined in row.xml.

	public View getView(int position, View convertView, ViewGroup parent) {
		View vi = convertView;

		if (convertView == null) {
			vi = inflater.inflate(R.layout.row, null);
			holder = new ViewHolder();
			holder.label = (TextView) vi.findViewById(R.id.title);
			holder.addr = (TextView) vi.findViewById(R.id.address);
			holder.image = (ImageView) vi.findViewById(R.id.icon);
			vi.setTag(holder);
		} else
			holder = (ViewHolder) vi.getTag();

		holder.label.setText(data.get(position).getTitle());
		holder.addr.setText(data.get(position).getPubDate());

		imageLoader.DisplayImage((data.get(position).getThumbnail()), activity,
				holder.image, 72, 72);

		return vi;
	}

Step 8: The List Item Layout

rssReader-3

Here is the row.xml which contains two textViews and Two Image Views. The textViews are for displaying the Title and the Short Description of the RSS Feed. And the ImageViews are for displaying the post image and the other for a right marker.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/widget30"
	android:layout_width="fill_parent" android:layout_height="wrap_content"
	android:padding="4dip" xmlns:android="http://schemas.android.com/apk/res/android">
	<TextView android:id="@+id/details" android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:text="TextView"
		android:textColor="#000000" android:layout_toRightOf="@+id/icon"
		android:layout_alignLeft="@+id/title" android:layout_alignRight="@+id/title"
		android:layout_below="@+id/title" android:layout_marginRight="5px">
	</TextView>
	<TextView android:id="@+id/title" android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:text="TextView"
		android:textStyle="bold" android:textColor="#000000"
		android:layout_marginTop="5px" android:layout_toRightOf="@+id/icon"
		android:layout_marginRight="5px">
	</TextView>
	<ImageView android:id="@+id/arrow" android:layout_width="wrap_content"
		android:layout_height="wrap_content" android:padding="0px"
		android:layout_marginRight="10px" android:src="@drawable/rightarrow"
		android:layout_alignRight="@+id/icon" android:layout_alignParentRight="true"
		android:layout_centerVertical="true">
	</ImageView>
	<ImageView android:id="@+id/thumb" android:layout_width="wrap_content"
		android:layout_height="wrap_content" android:layout_marginRight="10px"
		android:layout_centerVertical="true" android:layout_alignParentLeft="true">
	</ImageView>

</RelativeLayout>

Step 9: Loading the Images

You can use a Lazy image loader like the one i have used here from (Fedor Vlasov). You can add the class to your project.

Step 10: The POST Class

Now We will create a new class named Post to hold all the getters and setters for each article in the RSS Feed.
Here we used only a few attributes like the Title, Thumbnail, URL, Description and PubDate.

package com.xmlparse;

public class Post {

	private String title;
	private String thumbnail;
	private String url;
	private String description;
	private String pubDate;

	public String getTitle() {
		return title;
	}

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

	public String getThumbnail() {
		return thumbnail;
	}

	public void setThumbnail(String thumbnail) {
		this.thumbnail = thumbnail;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

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

	public String getDescription() {
		return description;
	}

	public void setPubDate(String pubDate) {
		this.pubDate = pubDate;
	}

	public String getPubDate() {
		return pubDate;
	}

}

Step 11: The SAX Paraser

Do not forget to add the INTERNET permission in the android manifest file

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

In this tutorial we will be using the SAX Parser to parse the RSS Feed. For the purpose of this tutorial we will be using this feed http://feeds.feedburner.com/theappleblog. The link refers to an XML file, you can right click on the webpage and click view source to see how the different tags are arranged in a feed.

Note:

SAX (Simple API for XML) is an event-based sequential access parser API developed by the XML-DEV mailing list for XML documents.

The SAXHelper class has the parseContent method which creates the SAXParser object and assigns a content handler to it then parses the URL.

	class SAXHelper {
		public HashMap<String, String> userList = new HashMap<String, String>();
		private URL url2;

		public SAXHelper(String url1) throws MalformedURLException {
			this.url2 = new URL(url1);
		}

		public RSSHandler parseContent(String parseContent) {
			RSSHandler df = new RSSHandler();
			try {

				SAXParserFactory spf = SAXParserFactory.newInstance();
				SAXParser sp = spf.newSAXParser();
				XMLReader xr = sp.getXMLReader();
				xr.setContentHandler(df);
				xr.parse(new InputSource(url2.openStream()));
			} catch (Exception e) {
				e.printStackTrace();
			}
			return df;
		}
	}

Step 13: The RSS Handler

rssReader-1

Here we extend the DefaultHandler class, lets name it RSSHandler. Eclipse automatically add all the unimplemented methods in the DefaultHandler class.
Now, the SAXParser traverses through the entire RSSFeed i.e our XML file and whenever it comes across an opening tag (eg:) the <strong>startElement </strong>method gets called and the <strong>localName </strong>variable gets the name of the tag(in this case localname=title).<br /> Now, every time when an ending tag (eg:) occurs then the endElement method gets called and the localname variable gets assigned with its name.
also, When the SAXParser comes across any text after a tag(eg:) then the characters method gets called.
Now we will have to add functionality to the class such that it reads in the data between these tags and stores them in an array with which we will be populating our listView.

	class RSSHandler extends DefaultHandler {

		private Post currentPost = new Post();
		StringBuffer chars = new StringBuffer();

		@Override
		public void startElement(String uri, String localName, String qName,
				Attributes atts) {

			chars = new StringBuffer();
			if (localName.equalsIgnoreCase("item")) {

			}
		}

		@Override
		public void endElement(String uri, String localName, String qName)
				throws SAXException {

			if (localName.equalsIgnoreCase("title")
					&& currentPost.getTitle() == null) {
				currentPost.setTitle(chars.toString());

			}
			if (localName.equalsIgnoreCase("pubDate")
					&& currentPost.getPubDate() == null) {
				currentPost.setPubDate(chars.toString());

			}
			if (localName.equalsIgnoreCase("thumbnail")
					&& currentPost.getThumbnail() == null) {
				currentPost.setThumbnail(chars.toString());

			}
			if (localName.equalsIgnoreCase("link")
					&& currentPost.getUrl() == null) {
				currentPost.setUrl(chars.toString());
			}

			if (localName.equalsIgnoreCase("item")) {
				PostList.add(currentPost);
				currentPost = new Post();
			}

		}

		@Override
		public void characters(char ch[], int start, int length) {
			chars.append(new String(ch, start, length));
		}

	}

Step 14: The RSS Handler

The final Application looks something like this…

Thats it!!

Thank you for following this tutorial, I hope you have followed all the parts of this tutorial. If you did’nt you can feel free to post your doubts in the comments section.

Download the Source code

Similar topics you might like…

    None Found

Share this Post and become one of us...