Wanna parse RSS feeds using your Android pimp-mobile….well, here’s how!
ROME is my all time fav in terms of Java RSS syndication feed parsing. It has some nifty features such as HTTP conditional GETs, ETags and GZip compression. It also covers a wide range of formats from RSS 0.90 – RSS 2.0, and Atom 0.3 & 1.0.
NOTES:
- Modify your AndroidManifest.xml to allow for internet browsing.
- Download the appropriate JAR files.
- There are differences in versions, and requires the jdom library. The version that worked for me are included in my download link provided:
- rome-0.9.jar
- jdom-1.0.jar
Download: AndroidRss.zip
File: AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.pfizer.android" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".AndroidRss" 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-permission android:name="android.permission.INTERNET"></uses-permission> </manifest>
File: main.xml
<?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"> <TableLayout android:id="@+id/table" android:layout_width="fill_parent" android:layout_height="wrap_content" android:stretchColumns="0"> <TableRow android:id="@+id/top_add_entry_row" android:layout_height="wrap_content" android:layout_width="fill_parent"> <EditText android:id="@+id/rssURL" android:hint="Enter RSS URL" android:singleLine="true" android:maxLines="1" android:maxWidth="220dp" android:layout_width="wrap_content" android:layout_height="wrap_content"> </EditText> <Button android:id="@+id/goButton" android:text="Go" android:layout_width="fill_parent" android:layout_height="wrap_content"> </Button> </TableRow> </TableLayout> <!-- Mid Panel --> <ListView android:id="@+id/ListView" android:layout_weight="1" android:layout_width="fill_parent" android:layout_height="wrap_content"> </ListView> <Button android:id="@+id/clearButton" android:text="Clear" android:layout_width="fill_parent" android:layout_height="wrap_content"> </Button> </LinearLayout>
File: AndroidRss.java
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;
public class AndroidRss extends Activity
{
/** Called when the activity is first created. */
private int selectedItemIndex = 0;
private final ArrayList list = new ArrayList();
private EditText text;
private ListView listView;
private Button goButton;
private Button clearButton;
private ArrayAdapter adapter = null;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
text = (EditText) this.findViewById(R.id.rssURL);
goButton = (Button) this.findViewById(R.id.goButton);
goButton.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
String rss = text.getText().toString().trim();
getRSS(rss);
}
});
clearButton = (Button) this.findViewById(R.id.clearButton);
clearButton.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
adapter.clear();
adapter.notifyDataSetChanged();
}
});
listView = (ListView) this.findViewById(R.id.ListView);
listView.setOnItemClickListener(new OnItemClickListener()
{
@Override
public void onItemClick(AdapterView parent, View view, int position, long duration)
{
selectedItemIndex = position;
Toast.makeText(getApplicationContext(), "Selected " + adapter.getItem(position) + " @ " + position, Toast.LENGTH_SHORT).show();
}
});
adapter = new ArrayAdapter(this, R.layout.dataview, R.id.ListItemView);
listView.setAdapter(adapter);
}
private void getRSS(String rss)
{
URL feedUrl;
try
{
Log.d("DEBUG", "Entered:" + rss);
feedUrl = new URL(rss);
SyndFeedInput input = new SyndFeedInput();
SyndFeed feed = input.build(new XmlReader(feedUrl));
List entries = feed.getEntries();
Toast.makeText(this, "#Feeds retrieved: " + entries.size(), Toast.LENGTH_SHORT);
Iterator iterator = entries.listIterator();
while (iterator.hasNext())
{
SyndEntry ent = (SyndEntry) iterator.next();
String title = ent.getTitle();
adapter.add(title);
}
adapter.notifyDataSetChanged();
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
catch (IllegalArgumentException e)
{
e.printStackTrace();
}
catch (FeedException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
private void clearTextFields()
{
Log.d("DEBUG", "clearTextFields()");
this.text.setText("");
}
}

Keep the posting up. I never thought I would find an individual that had close to the same grasp of worldly knowldege , however, you are that beacon of hope in humanity!I hope you continue to bring your knowldge and enlightenment to the world and never let your expression be squelched! Live strong!
hey, very nice work.
one question. how do i open the webpage of the selected item? i mean, how do i read the out of the rss?
greetings
Hi Arthur,
With the ROME api , the feed URL, URI, images, categories…etc can be easilly retrieved.
For more details see:
https://rome.dev.java.net/apidocs/1_0/com/sun/syndication/feed/synd/SyndFeed.html
Simple:
You will notice the listview implements a OnItemClickListener with an onItem click.
I have made a Toast.makeText().show() where you can modify and include the URL.
A better way of handling this situation, would be to use the ViewHolder pattern:
1. Create a separate layout for each list item.
This is already done using dataview.xml. Modify it to include a TextView for URL , and ImageView for images.
2. Create a Java class to hold necessary data you want to display of the SyndEntry eg. url, date published, image etc…Basically, you are selecting only those fields from the SyndEntry you need.
3. Now the important part: Create a custom version of the ArrayAdapter
eg. RssArrayAdapter rssAdapter= new RssArrayAdapter
4. Override the getView( … ) and populate the row element…
That’s it!
The basic elements you will find by looking at some of my other posts above eg. creating a customizing an ArrayAdapter and overriding its getView() method…etc.
Keep well
Hello all!
I`m trying to set that OnItemClickListener to open the web browser but luck. I what to ask if you could show us an working example.
Thanks for your time.
Arthur,
Will put the code up…mmmh let’s make it next week..just ping me by email then!
Thank you so much for the tutorial. This has been incredibly helpful.
Now the issue I’m having… I’m trying to integrate what I learned from your tutorial and read an RSS feed. My adapter seems to be setup incorrectly. I need to read and display the feed on opening the screen versus as the result of a button click. When GetRSS is run, I can see the adapter gets populated correctly. However, when I attempt to set the ListView adapter to the populated adapter, my program force quits. Any ideas? My updated code looks like this:
adapter = new ArrayAdapter(this, R.layout.dataview, R.id.ListItemView);
getRSS("http://www.example.com/wp/?feed=gigpress&artist=1");
listView = (ListView) this.findViewById(R.id.ListView);
listView.setAdapter(adapter);
getRSS is unchanged from your example.
Hi Rob,
“I need to read and display the feed on opening the screen versus as the result of a button click.”
OK. i modified so it loads immediately , ie. No need to press any button.
(I removed the goButton reference)
I ran your URL: “http://www.example.com/wp/?feed=gigpress&artist=1″
nothing blank screen
….then I checked the LogCat – FileNotFound error….
I replaces your URL with CBC sports RSS feed link and viola – screenshot!
package com.pfizer.android;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;
public class AndroidRss extends Activity
{
/** Called when the activity is first created. */
private int selectedItemIndex = 0;
private final ArrayList list = new ArrayList();
private EditText text;
private ListView listView;
private Button goButton;
private Button clearButton;
private ArrayAdapter adapter = null;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
text = (EditText) this.findViewById(R.id.rssURL);
listView = (ListView) this.findViewById(R.id.ListView);
listView.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView parent, View view, int position, long duration)
{
selectedItemIndex = position;
Toast.makeText(getApplicationContext(), “Selected ” + adapter.getItem(position) + ” @ ” + position, Toast.LENGTH_SHORT).show();
}
});
adapter = new ArrayAdapter(this, R.layout.dataview, R.id.ListItemView);
listView.setAdapter(adapter);
getRSS(“http://rss.cbc.ca/lineup/topstories.xml”);
clearButton = (Button) this.findViewById(R.id.clearButton);
clearButton.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
adapter.clear();
adapter.notifyDataSetChanged();
}
});
}
private void getRSS(String rss)
{
URL feedUrl;
try
{
Log.d(“DEBUG”, “Entered:” + rss);
feedUrl = new URL(rss);
SyndFeedInput input = new SyndFeedInput();
SyndFeed feed = input.build(new XmlReader(feedUrl));
List entries = feed.getEntries();
Toast.makeText(this, “#Feeds retrieved: ” + entries.size(), Toast.LENGTH_SHORT);
Iterator iterator = entries.listIterator();
while (iterator.hasNext())
{
SyndEntry ent = (SyndEntry) iterator.next();
String title = ent.getTitle();
adapter.add(title);
}
adapter.notifyDataSetChanged();
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
catch (IllegalArgumentException e)
{
e.printStackTrace();
}
catch (FeedException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
private void clearTextFields()
{
Log.d(“DEBUG”, “clearTextFields()”);
this.text.setText(“”);
}
}
You put me right in the vicinity of my problem. Thanks so much for your help!
Hi,
I have a problem with the import com.sun, it’s like Eclipse doesn’t know this import.
Do you have any idea from where this problem could come ?
Thanks for the reply,
Nico
Hi Nico,
A good starting point is to download the complete source code for the tutorial: AndroidRss.zip (link is provided on the page), to look at the project structure.
In your Android Eclipse project, do the following:
1. Create a folder called libs/ in the root directory of your project.
2. Copy the JAR files from the ROME package into it ….(as in the AndroidRSS.zip )
3. Click on your project in the side pane, now RIGHT-CLICK and select Configure Build Path (or Project -> Properties -> Java Build Path)
4. Click Add External JARS and browse to the libs/ folder in your project
5. Add the JARS in the libs/ folder
6. On the same window, Click the tab Export, now select the JARS you have just added.
7. Click on Project -> Clean…
8. Your done!
If the problem remains…what is happening is that you may have warnings, set to errors in your compiler set-up.
You can get around this by doing:
1. Window -> Preferences -> Java -> Compiler -> Deprecated and Restricted API..
select Warnings and Click Signal use of Deprecated API…and Signal overriding or implemented…
that should make the errors which prevent compilation be interpreted as allowed warnings.
But its most likely just doing step about the Build Path and adding the ROME JARS to the build path.
Keep well,
-w
Hi Wagied,
I tried what you said and my errors are :
UNEXPECTED TOP-LEVEL EXCEPTION:
java.util.zip.ZipException: error in opening zip file
[2011-03-10 19:58:55 - RSSCooker]: Dx at java.util.zip.ZipFile.open(Native Method)
[2011-03-10 19:58:55 - RSSCooker]: Dx at java.util.zip.ZipFile.(ZipFile.java:127)
[2011-03-10 19:58:55 - RSSCooker]: Dx at java.util.zip.ZipFile.(ZipFile.java:144)
[2011-03-10 19:58:55 - RSSCooker]: Dx at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:205)
[2011-03-10 19:58:55 - RSSCooker]: Dx at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:130)
[2011-03-10 19:58:55 - RSSCooker]: Dx at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:108)
[2011-03-10 19:58:55 - RSSCooker]: Dx at com.android.dx.command.dexer.Main.processOne(Main.java:313)
[2011-03-10 19:58:55 - RSSCooker]: Dx at com.android.dx.command.dexer.Main.processAllFiles(Main.java:233)
[2011-03-10 19:58:55 - RSSCooker]: Dx at com.android.dx.command.dexer.Main.run(Main.java:185)
[2011-03-10 19:58:55 - RSSCooker]: Dx at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[2011-03-10 19:58:55 - RSSCooker]: Dx at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[2011-03-10 19:58:55 - RSSCooker]: Dx at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[2011-03-10 19:58:55 - RSSCooker]: Dx at java.lang.reflect.Method.invoke(Method.java:597)
[2011-03-10 19:58:55 - RSSCooker]: Dx at com.android.ide.eclipse.adt.internal.build.DexWrapper.run(Unknown Source)
[2011-03-10 19:58:55 - RSSCooker]: Dx at com.android.ide.eclipse.adt.internal.build.BuildHelper.executeDx(Unknown Source)
[2011-03-10 19:58:55 - RSSCooker]: Dx at com.android.ide.eclipse.adt.internal.build.builders.PostCompilerBuilder.build(Unknown Source)
[2011-03-10 19:58:55 - RSSCooker]: Dx at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:627)
[2011-03-10 19:58:55 - RSSCooker]: Dx at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
[2011-03-10 19:58:55 - RSSCooker]: Dx at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:170)
[2011-03-10 19:58:55 - RSSCooker]: Dx at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:201)
[2011-03-10 19:58:55 - RSSCooker]: Dx at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:253)
[2011-03-10 19:58:55 - RSSCooker]: Dx at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
[2011-03-10 19:58:55 - RSSCooker]: Dx at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:256)
[2011-03-10 19:58:55 - RSSCooker]: Dx at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:309)
[2011-03-10 19:58:55 - RSSCooker]: Dx at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:341)
[2011-03-10 19:58:55 - RSSCooker]: Dx at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:140)
[2011-03-10 19:58:55 - RSSCooker]: Dx at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:238)
[2011-03-10 19:58:55 - RSSCooker]: Dx at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
[2011-03-10 19:58:55 - RSSCooker]: Dx2 errors; aborting
[2011-03-10 19:58:55 - RSSCooker] Conversion to Dalvik format failed with error 1
This will help maybe
Nico
Hi,
is your code fast? Because a similar project : http://code.google.com/p/android-rome-feed-reader/ is very slow.
Guillaume
ROME was basically developed by SUN’s (now Oracle) for RSS feed parsersing. Its been widely used…just google it.
I was’nt aware that there is a project that you mentioned…since its very fast on its own- that’s the way I use it.
Regards,
-w
Hello
Please note that you did not include the jar files!
Take a look into your .classhpath file:
”
“
Well I guess I can’t write xml content here
I cant execute the code due to there is some error~ any expert can guide me? i need it urgently ><
why i just able to retrieve 1 RSS Feed which is
http://rss.cbc.ca/lineup/topstories.xml
the others all not working
Thank you so much for the example.
Everything is working fine, except one thing:
SyndFeed feed = input.build(new XmlReader(feedUrl));
Executing this line takes up to 45 seconds. Any ideas?
Thank you, Andrew