I created an app that is going to download an xml file,then parse it, and adapt it to a list view, but I faced a problem in parsing xml, first thing first:
MainActivity.java
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
downloadData downloadData = new downloadData();
downloadData.execute("http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/topfreeapplications/limit=10/xml");
}
private class downloadData extends AsyncTask<String, Void, String> {
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
ParseApplications parseApplications = new ParseApplications();
parseApplications.parse(s);
}
#Override
protected String doInBackground(String... params) {
String rssFeed = downloadXML(params[0]);
if (rssFeed == null) {
}
return rssFeed;
}
private String downloadXML(String urlPath) {
StringBuilder xmlResult = new StringBuilder();
try {
URL url = new URL(urlPath);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
int charsRead;
char[] inputBuffer = new char[500];
while (true) {
charsRead = reader.read(inputBuffer);
if (charsRead < 0) {
break;
}
if (charsRead > 0) {
xmlResult.append(String.copyValueOf(inputBuffer), 0, charsRead);
}
}
reader.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
return xmlResult.toString();
}
}
}
MainActivity.class work well in term of downloading XML, but when it comes to parsing xml, although it parses it,but return no value:
ParseApplications.java
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.StringReader;
import java.util.ArrayList;
public class ParseApplications {
private ArrayList<FeedEntry> applications;
public ParseApplications() {
this.applications = new ArrayList<>();
}
public ArrayList<FeedEntry> getApplications() {
return applications;
}
public boolean parse(String xmlData) {
boolean status = true;
FeedEntry currentRecord = null;
boolean inEntry = false;
String textValue = "";
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(new StringReader(xmlData));
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
String tagName = xpp.getName();
switch (eventType) {
case XmlPullParser.START_TAG:
if ("entry".equalsIgnoreCase(tagName)) {
inEntry = true;
currentRecord = new FeedEntry();
}
break;
case XmlPullParser.TEXT:
textValue = xpp.getText();
break;
case XmlPullParser.END_TAG:
if (inEntry) {
if ("entry".equalsIgnoreCase(tagName)) {
applications.add(currentRecord);
inEntry = false;
} else if ("name".equalsIgnoreCase(tagName)) {
currentRecord.setName(textValue);
} else if ("artist".equalsIgnoreCase(tagName)) {
currentRecord.setArtist(textValue);
} else if ("releaseDate".equalsIgnoreCase(tagName)) {
currentRecord.setReleaseDate(textValue);
} else if ("image".equalsIgnoreCase(tagName)) {
currentRecord.setImageURL(textValue);
} else if ("summary".equalsIgnoreCase(tagName)) {
currentRecord.setSummary(textValue);
}
}
break;
default:
//Nothing to do
eventType = xpp.next();
}
}
} catch (Exception e) {
status = false;
e.printStackTrace();
}
return status;
}
}
here is the other class:
FeedEntry.java
public class FeedEntry {
private String name;
private String artist;
private String releaseDate;
private String summary;
private String imageURL;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public String getReleaseDate() {
return releaseDate;
}
public void setReleaseDate(String releaseDate) {
this.releaseDate = releaseDate;
}
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getImageURL() {
return imageURL;
}
public void setImageURL(String imageURL) {
this.imageURL = imageURL;
}
#Override
public String toString() {
return "name='" + name + '\n' +
", artist='" + artist + '\n' +
", releaseDate='" + releaseDate + '\n' +
", imageURL='" + imageURL;
}
}
I think I am a quiet bit late but still, it can help other also. So I am posting my answer. Please check the parse method once you are stuck at first tag only.It should be like this
public boolean parse(String xmlData) {
boolean status = true;
FeedEntry currentRecord = null;
boolean inEntry = false;
String textValue = "";
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(new StringReader(xmlData));
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
String tagName = xpp.getName();
switch (eventType) {
case XmlPullParser.START_TAG:
if (tagName.equalsIgnoreCase("entry")) {
inEntry = true;
currentRecord = new FeedEntry();
}
break;
case XmlPullParser.TEXT:
textValue = xpp.getText();
break;
case XmlPullParser.END_TAG:
if (inEntry) {
if (tagName.equalsIgnoreCase("entry")) {
applications.add(currentRecord);
inEntry = false;
} else if (tagName.equalsIgnoreCase("name")) {
currentRecord.setName(textValue);
} else if (tagName.equalsIgnoreCase("artist")) {
currentRecord.setArtist(textValue);
} else if (tagName.equalsIgnoreCase("releaseDate")) {
currentRecord.setReleaseDate(textValue);
} else if (tagName.equalsIgnoreCase("image")) {
currentRecord.setImageURL(textValue);
} else if (tagName.equalsIgnoreCase("summary")) {
currentRecord.setSummary(textValue);
}
}
break;
default:
//Nothing to do
break;
}
eventType = xpp.next(); // this should come after switch case
}
} catch (
Exception e
)
{
status = false;
e.printStackTrace();
}
return status;
}
In the XmlPullParser.END_TAG: case:
Try to remove "inEntry = false;"
Related
i want to make rss reader app.
i want to get rss first then pass it into another activity use intent.
here is my codes:
mainActivity.java
public class mainActivity extends Activity {
new AsyncTaskParseJson().execute();
}
public class AsyncTaskParseJson extends AsyncTask<String, String, String> {
protected String doInBackground(String... arg0) {
RssParser parser = new RssParser("https://test/feed/");
Bundle extra = new Bundle();
extra.putSerializable("objects", parser);
Intent intent = new Intent(this, b.class);
intent.putExtra("extra", extra);
startActivity(intent);
}
}
RssParser.java
import java.io.IOException;
import java.io.Serializable;
import java.io.StringReader;
import java.net.URL;
import java.util.ArrayList;
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 org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
public class RssParser extends DefaultHandler implements Serializable {
private StringBuilder content;
private boolean inChannel;
private boolean inImage;
private boolean inItem;
private ArrayList<Item> items = new ArrayList<Item>();
private Channel channel = new Channel();
private Item lastItem;
public RssParser(String url) {
try {
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
URL sourceUrl = new URL(url);
xr.setContentHandler(this);
xr.parse(new InputSource(sourceUrl.openStream()));
}
catch (ParserConfigurationException e) {
e.printStackTrace();
}
catch (SAXException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
public class Item {
public String title;
public String description;
public String link;
public String category;
public String pubDate;
public String guid;
public String imageUrl;
public String creator;
}
public class Channel {
public String title;
public String description;
public String link;
public String lastBuildDate;
public String generator;
public String imageUrl;
public String imageTitle;
public String imageLink;
public String imageWidth;
public String imageHeight;
public String imageDescription;
public String language;
public String copyright;
public String pubDate;
public String category;
public String ttl;
}
#Override
public void startDocument() throws SAXException {
// Log.i("LOG", "StartDocument");
}
#Override
public void endDocument() throws SAXException {
// Log.i("LOG", "EndDocument");
}
#Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
if (localName.equalsIgnoreCase("image")) {
inImage = true;
}
if (localName.equalsIgnoreCase("channel")) {
inChannel = true;
}
if (localName.equalsIgnoreCase("item")) {
lastItem = new Item();
items.add(lastItem);
inItem = true;
}
content = new StringBuilder();
}
#Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (localName.equalsIgnoreCase("image")) {
inImage = false;
}
if (localName.equalsIgnoreCase("channel")) {
inChannel = false;
}
if (localName.equalsIgnoreCase("item")) {
inItem = false;
}
if (localName.equalsIgnoreCase("title")) {
if (content == null) {
return;
}
if (inItem) {
lastItem.title = content.toString();
} else if (inImage) {
channel.imageTitle = content.toString();
} else if (inChannel) {
channel.title = content.toString();
}
content = null;
}
if (localName.equalsIgnoreCase("dc:creator") || localName.equalsIgnoreCase("creator")) {
if (content == null) {
return;
}
lastItem.creator = content.toString();
content = null;
}
if (localName.equalsIgnoreCase("description")) {
if (content == null) {
return;
}
if (inItem) {
lastItem.description = android.text.Html.fromHtml(content.toString()).toString().substring(1);
lastItem.imageUrl = this.extractImageUrl(content.toString());
} else if (inImage) {
channel.imageDescription = content.toString();
} else if (inChannel) {
channel.description = android.text.Html.fromHtml(content.toString()).toString().substring(1);
}
content = null;
}
if (localName.equalsIgnoreCase("link")) {
if (content == null) {
return;
}
if (inItem) {
lastItem.link = content.toString();
} else if (inImage) {
channel.imageLink = content.toString();
} else if (inChannel) {
channel.link = content.toString();
}
content = null;
}
if (localName.equalsIgnoreCase("category")) {
if (content == null) {
return;
}
if (inItem) {
lastItem.category = content.toString();
} else if (inChannel) {
channel.category = content.toString();
}
content = null;
}
if (localName.equalsIgnoreCase("pubDate")) {
if (content == null) {
return;
}
if (inItem) {
lastItem.pubDate = content.toString();
} else if (inChannel) {
channel.pubDate = content.toString();
}
content = null;
}
if (localName.equalsIgnoreCase("guid")) {
if (content == null) {
return;
}
lastItem.guid = content.toString();
content = null;
}
if (localName.equalsIgnoreCase("url")) {
if (content == null) {
return;
}
channel.imageUrl = content.toString();
content = null;
}
if (localName.equalsIgnoreCase("width")) {
if (content == null) {
return;
}
channel.imageWidth = content.toString();
content = null;
}
if (localName.equalsIgnoreCase("height")) {
if (content == null) {
return;
}
channel.imageHeight = content.toString();
content = null;
}
if (localName.equalsIgnoreCase("language")) {
if (content == null) {
return;
}
channel.language = content.toString();
content = null;
}
if (localName.equalsIgnoreCase("copyright")) {
if (content == null) {
return;
}
channel.copyright = content.toString();
content = null;
}
if (localName.equalsIgnoreCase("ttl")) {
if (content == null) {
return;
}
channel.ttl = content.toString();
content = null;
}
}
private String extractImageUrl(String description) {
XmlPullParserFactory factory = null;
try {
factory = XmlPullParserFactory.newInstance();
}
catch (XmlPullParserException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
XmlPullParser xpp = null;
try {
xpp = factory.newPullParser();
}
catch (XmlPullParserException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
xpp.setInput(new StringReader(description));
}
catch (XmlPullParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int eventType = 0;
try {
eventType = xpp.getEventType();
}
catch (XmlPullParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG && "img".equals(xpp.getName())) {
//found an image start tag, extract the attribute 'src' from here...
return xpp.getAttributeValue(null, "src").toString();
}
try {
eventType = xpp.next();
}
catch (XmlPullParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return xpp.getAttributeValue(null, "src").toString();
}
#Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (content == null) {
return;
}
content.append(ch, start, length);
}
public Item getItem(int index) {
return items.get(index);
}
public ArrayList<Item> getItems() {
return items;
}
}
second activity that i want to get RssParser Items:
b.java
Bundle extra = getIntent().getBundleExtra("extra");
RssParser p = (RssParser) extra.getSerializable("objects");
ListView listView = (ListView) findViewById(R.id.content_frame);
listView.setAdapter((ListAdapter) p.getItems());
and i always get errors like:
java.lang.RuntimeException: Parcelable encountered IOException writing serializable object
java.lang.RuntimeException: Parcel: unable to marshal value
Caused by: java.lang.RuntimeException: Parcelable encountered IOException reading a Serializable object
if any suggestion i really Thankful.
Best Regards
In this case, instead of extending from Serializable, extend from Parcelable.
And, when sending, use:
RssParser parser = new RssParser("https://test/feed/");
Bundle extra = new Bundle();
extra.putParcelable("objects", parser);
Reception of it:
RssParser rssParser = getIntent().getExtras().getParcelable("objects");
Works like that, not precisely the best option, but works.
The error mainly said that was found a Serializable when a Parcelable was received. So, I changed it to Parcelable.
EDIT
gradle:
dependencies {
//...
compile 'com.google.code.gson:gson:2.2.4'
}
Send:
Intent intent = new Intent(MainActivity.this, b.class);
intent.putExtra("extra", new Gson().toJson(parser));
startActivity(intent);
Receive:
String toParse = getIntent().getExtras().getString("extra");
RssParser rssParser = new Gson().fromJson(toParse, RssParser.class);
From the edit, i was tested. It works.
EDIT2
If, you need to pass a Array or List:
Type rssListType = new TypeToken<ArrayList<RssParser>>(){}.getType();
List<RssParser> founderList = new Gson().fromJson(myStringToParse, rssListType);
Regards.
I'm trying to develop a simple application that reads rss feeds from a certain URL and then displays the results in a list view.
Here is my rss reader, which is the main thing in the app:
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
public class RssReader {
private String title = null;
private String link = null;
private String description = null;
private ArrayList<RssItem> posts = new ArrayList<RssItem>();
private Thread thread;
private String urlString = null;
private XmlPullParserFactory xmlFactoryObject;
public volatile boolean parsingComplete = true;
public RssReader(String url) {
this.urlString = url;
}
public boolean getParsingComplete() {
return this.parsingComplete;
}
public ArrayList<RssItem> getPosts() {
return posts;
}
public void parseXML(XmlPullParser parser) {
int event;
try {
event = parser.getEventType();
while (event != XmlPullParser.END_DOCUMENT) {
String name = parser.getName();
switch (event) {
case XmlPullParser.START_TAG:
break;
case XmlPullParser.END_TAG:
if (name.equals("title")) {
title = parser.getText();
} else if (name.equals("link")) {
link = parser.getText();
} else if (name.equals("description")) {
description = parser.getText();
}
break;
}
if(title != null && link != null && description != null) {
RssItem item = new RssItem(this.title,this.description,this.link);
posts.add(item);
this.title = this.description = this.link = null;
}
event = parser.next();
}
parsingComplete = false;
} catch (Exception e) {
e.printStackTrace();
}
}
public void fetchXML() {
thread = new Thread(new Runnable() {
#Override
public void run() {
try {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query
conn.connect();
InputStream stream = conn.getInputStream();
xmlFactoryObject = XmlPullParserFactory.newInstance();
XmlPullParser myparser = xmlFactoryObject.newPullParser();
myparser.setFeature(
XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
myparser.setInput(stream, null);
parseXML(myparser);
stream.close();
} catch (Exception e) {
} finally {
parsingComplete = true;
}
}
});
thread.start();
}
And here is my MainActivity:
package com.example.ynetrssproject;
import java.util.ArrayList;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.widget.ListView;
import android.os.Bundle;
public class MainActivity extends ActionBarActivity {
private ListView news;
private String rssUrl = "http://www.themarker.com/cmlink/1.144";
private ArrayList<RssItem> list;
private RssItemAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
news = (ListView) findViewById(R.id.news);
RssReader reader = new RssReader(rssUrl);
reader.fetchXML();
while(true) {
Log.d("Runnning", "Run");
if(reader.getParsingComplete()) {
list = reader.getPosts();
break;
}
}
adapter = new RssItemAdapter(this, R.layout.post_item_list, list);
news.setAdapter(adapter);
}
}
The problem is that everytime I call fetchXML, eventually it returns me an empty ArrayList. Therefore, my listview keeps being empty.
My adapter isn't such a big deal. It works fine. The problem is that I keep getting an empty array list from the object RssReader. I know this because I performed a little if statement at the end of the code just to check if the ArrayList is empty.
P.S I have tried with multiple RSS urls but none of them works.
Also, I added the permission of Internet in my manifest.
use SAXParser
public class RssParseHandler extends DefaultHandler {
private List<RssItem> rssItems;
private RssItem currentItem;
private boolean parsingTitle;
private boolean parsingLink;
public RssParseHandler() {
rssItems = new ArrayList<RssItem>();
}
public List<RssItem> getItems() {
return rssItems;
}
#Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if ("item".equals(qName)) {
currentItem = new RssItem();
} else if ("title".equals(qName)) {
parsingTitle = true;
} else if ("link".equals(qName)) {
parsingLink = true;
}
}
#Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if ("item".equals(qName)) {
rssItems.add(currentItem);
currentItem = null;
}else if ("title".equals(qName)) {
parsingTitle = false;
}else if ("link".equals(qName)) {
parsingLink = 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 (parsingLink) {
if (currentItem != null) {
currentItem.setLink(new String(ch, start, length));
parsingLink = false;
}
}
}
}
public class RssItem {
// item title
private String title;
// item link
private String link;
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
#Override
public String toString() {
return title;
}
}
In my xml, i have <ns5:Name>mil & carbon</ns5:Name>
From my java code i am retrieving that value by
public class MasterdataParser extends MasterdataBaseParser {
protected MasterdataParser(InputStream response) {
super(response);
}
public MasterData parse() {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
MasterData masterData;
try {
DocumentBuilder builder = factory.newDocumentBuilder();
Document dom = builder.parse(this.getInputStream());
Element root = dom.getDocumentElement();
masterData = new MasterData();
NodeList list;
Element element;
NodeList childNodeList;
Node node;
String nodeName;
list = root.getElementsByTagName(PREFIX+CATEGORY);
for (int i=0;i<list.getLength();i++){
element = (Element) list.item(i);
childNodeList = element.getChildNodes();
Category category = new Category();
for (int j = 0; j < childNodeList.getLength(); j++) {
node = childNodeList.item(j);
nodeName = node.getNodeName();
if (nodeName.equalsIgnoreCase(PREFIX+CATEGORY_ID)) {
try{
category.setId(node.getFirstChild().getNodeValue());
} catch (NullPointerException ex) {
category.setId(null);
}
}
if (nodeName.equalsIgnoreCase(PREFIX+CATEGORY_NAME)) {
try{
// System.out.println("Masterdataparser category name html "+Html.fromHtml(node.getFirstChild().getNodeValue())); // Not worked
System.out.println("URL Decoder "+URLDecoder.decode(node.getFirstChild().getNodeValue(), "UTF-8")); // Not worked
category.setName(node.getFirstChild().getNodeValue());
} catch (NullPointerException ex) {
category.setName(null);
}
}
}
public abstract class MasterdataBaseParser implements MasterdataParserInterface {
static final String CATEGORY = "Category";
static final String CATEGORY_ID = "Id";
static final String CATEGORY_NAME = "Name";
final InputStream response;
protected MasterdataBaseParser(InputStream response){
this.response = response;
}
protected InputStream getInputStream() {
return response;
}
}
But it displays only "mil" and it is not taking "&" as "&". But i want to display "mil & carbon". How to do this one? Advance thanks for any help
Here is an example of how i do things with one class parser and several xml stream :
public class RSSHandler extends DefaultHandler {
int RSS_ID;
ContentValues parsedValues = new ContentValues();
private String parsedString = null;
protected DataController _dataController;
private StringBuffer parsedBuffer = new StringBuffer();
public void setRssId(int rssId) {
RSS_ID = rssId;
}
public void setDataController(DataController dataController) {
_dataController = (DataController) dataController;
}
#Override
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
}
#Override
public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
parsedString = parsedString.trim();
switch (RSS_ID) {
case (0):
if (localName.equals("Application")) {
_dataController.insertRowInTable(RSS_ID, parsedValues);
}
else {
parsedValues.put(localName, parsedString);
}
break;
case (1):
if (localName.equals("tab")) {
_dataController.insertRowInTable(RSS_ID, parsedValues);
}
else {
parsedValues.put(localName, parsedString);
}
break;
case (2):
if (localName.equals("category")) {
_dataController.insertRowInTable(RSS_ID, parsedValues);
}
else {
parsedValues.put(localName, parsedString);
}
break;
case (3):
if (localName.equals("item")) {
_dataController.insertRowInTable(RSS_ID, parsedValues);
}
else {
parsedValues.put(localName, parsedString);
}
break;
case (4):
if (localName.equals("event")) {
_dataController.insertRowInTable(RSS_ID, parsedValues);
}
else {
parsedValues.put(localName, parsedString);
}
break;
case (5):
if (localName.equals("album")) {
_dataController.insertRowInTable(RSS_ID, parsedValues);
}
else {
parsedValues.put(localName, parsedString);
}
break;
case (6):
if (localName.equals("picture")) {
_dataController.insertRowInTable(RSS_ID, parsedValues);
}
else {
parsedValues.put(localName, parsedString);
}
break;
case (7):
if (localName.equals("location")) {
_dataController.insertRowInTable(RSS_ID, parsedValues);
}
else {
parsedValues.put(localName, parsedString);
}
break;
default:
break;
}
parsedString = "";
parsedBuffer = new StringBuffer();
}
#Override
public void characters(char ch[], int start, int length) {
parsedBuffer.append(ch, start, start + length);
parsedString = parsedBuffer.toString();
}
}
DataController is just a global class to acces methods and attributes.
public void insertRowInTable(int tableId, ContentValues myRow) {
String myTable = _tableNameList.get(tableId);
_dataBaseHelper.createRowInTable(myTable, myRow);
}
public void createRowInTable(String tableName, ContentValues values) {
try {
myDataBase.insert(tableName, null, values);
}
catch (Exception e) {
//catch
}
}
While parsing xml, by default "&" is behaving as "Escape sequence"(In android lower version like 2.2) that's why i can't able to parse that "mil & carbon". So before parsing, i replaced "&" with "ampersand"(In words) under the file and after fetching that node as "mil ampersand carbon" then replacing the "ampersand" with "&"(symbol). And lots of thanks to "Yume" sir
I am trying to parse rss feed in honeycomb 3.0 but it gives error as follows.
ERROR/AndroidNews::PullFeedParser(444): android.os.NetworkOnMainThreadException
I tried same code in android lower version it works but it doesn't work in Honeycomb.
Please suggest some help
This is in main activity
try{
FeedParser parser = new XmlPullFeedParser(feedUrl);
messages = parser.parse();
titles = new ArrayList<String>(messages.size());
String description ="";//= new ArrayList<String>(messages.size());
for (Message msg : messages){
description = msg.getDescription().toString();
Log.v("Desc", description);
titles.add(description);
}
} catch (Throwable t){
Log.e("AndroidNews",t.getMessage(),t);
}
I am using XmlPullFeedParser which extends BaseFeedParser
public class XmlPullFeedParser extends BaseFeedParser {
public XmlPullFeedParser(String feedUrl) {
super(feedUrl);
}
public List<Message> parse() {
List<Message> messages = null;
XmlPullParser parser = Xml.newPullParser();
try {
// auto-detect the encoding from the stream
parser.setInput(this.getInputStream(), null);
int eventType = parser.getEventType();
Message currentMessage = null;
boolean done = false;
while (eventType != XmlPullParser.END_DOCUMENT && !done){
String name = null;
switch (eventType){
case XmlPullParser.START_DOCUMENT:
messages = new ArrayList<Message>();
break;
case XmlPullParser.START_TAG:
name = parser.getName();
if (name.equalsIgnoreCase(ITEM)){
currentMessage = new Message();
} else if (currentMessage != null){
if (name.equalsIgnoreCase(LINK)){
currentMessage.setLink(parser.nextText());
} else if (name.equalsIgnoreCase(DESCRIPTION)){
currentMessage.setDescription(parser.nextText());
} else if (name.equalsIgnoreCase(PUB_DATE)){
currentMessage.setDate(parser.nextText());
} else if (name.equalsIgnoreCase(TITLE)){
currentMessage.setTitle(parser.nextText());
}
}
break;
case XmlPullParser.END_TAG:
name = parser.getName();
if (name.equalsIgnoreCase(ITEM) && currentMessage != null){
messages.add(currentMessage);
} else if (name.equalsIgnoreCase(CHANNEL)){
done = true;
}
break;
}
eventType = parser.next();
}
} catch (Exception e) {
Log.e("AndroidNews::PullFeedParser", e.getMessage(), e);
throw new RuntimeException(e);
}
return messages;
}
}
This is BaseFeedParser:
public class BaseFeedParser implements FeedParser {
// names of the XML tags
static final String CHANNEL = "channel";
static final String PUB_DATE = "pubDate";
static final String DESCRIPTION = "description";
static final String LINK = "link";
static final String TITLE = "title";
static final String ITEM = "item";
static final String BODY = "body";
private final URL feedUrl;
protected BaseFeedParser(String feedUrl){
try {
this.feedUrl = new URL(feedUrl);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
protected InputStream getInputStream() {
try {
return feedUrl.openConnection().getInputStream();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public List<Message> parse() {
// TODO Auto-generated method stub
return null;
}
}
This is FeedParser:
public interface FeedParser {
List<Message> parse();
}
This is message class:
public class Message implements Comparable<Message>{
static SimpleDateFormat FORMATTER =
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
private String title;
private URL link;
private String description;
private Date date;
private String body;
public String getTitle() {
return title;
}
public String getBody() {
return body;
}
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;
copy.body = body;
return copy;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Title: ");
sb.append(title);
sb.append("Body: ");
sb.append(body);
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;
} else if (!body.equals(other.body))
return false;
return true;
}
public int compareTo(Message another) {
if (another == null) return 1;
// sort descending, most recent first
return another.date.compareTo(date);
}
}
The error message here pretty much tells you what is going on -- you are trying to access the network on tthe main thread. You really shouldn't do that on any version of android, because it can (read: will) cause your UI to hang while the connection is processing.
There are ways to turn the error off, but I won't get into tthem: you shouodnt do it.
instead, you want to do this work in aa background thread and post a minimal handler back to the UI thread. I don't have an example handy (on my tablet now) but let me know if you cannot find one.
..edit..
OK, here's a simple example. This requires an activity with a text view (id "text") and, of course, INTERNET permissions. Let me know if you have any questions!
public class MainActivity extends Activity {
private TextView mTextView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTextView = (TextView) findViewById(R.id.text);
// start our call in a new thread
(new Thread(new Runnable() {
#Override
public void run() {
fetchPage();
}
})).start();
}
private void fetchPage() {
try {
URL url = new URL("http://stackoverflow.com/feeds");
HttpURLConnection c = (HttpURLConnection) url.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
InputStream is = c.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ((len1 = is.read(buffer)) != -1) {
bos.write(buffer, 0, len1);
}
bos.close();
is.close();
// Remember, all UI things must occur back on the UI thread!
final String text = bos.toString();
this.runOnUiThread(new Runnable() {
#Override
public void run() {
mTextView.setText(text);
}
});
} catch (final IOException ioe) {
this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this, ioe.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
}
thanks,
--randy
I am new to android and i am trying to build a RSS reader for Android. I have built all the classes and XML files but its not giving the required output. Its just showing the message
No RSS feed available.
Please can some one suggest what should i do.
Here is the code which i took from the tutorial and tried to manipulate-
public final String RSSFEEDOFCHOICE = "http://blog.01synergy.com/feed/";
public final String tag = "RSSReader";
private RSSFeed feed = null;
/** Called when the activity is first created. */
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
// go get our feed!
feed = getFeed(RSSFEEDOFCHOICE);
// display UI
UpdateDisplay();
}
private RSSFeed getFeed(String urlToRssFeed)
{
try
{
// setup the url
URL url = new URL(urlToRssFeed);
// create the factory
SAXParserFactory factory = SAXParserFactory.newInstance();
// create a parser
SAXParser parser = factory.newSAXParser();
// create the reader (scanner)
XMLReader xmlreader = parser.getXMLReader();
// instantiate our handler
RSSHandler theRssHandler = new RSSHandler();
// assign our handler
xmlreader.setContentHandler(theRssHandler);
// get our data via the url class
InputSource is = new InputSource(url.openStream());
// perform the synchronous parse
xmlreader.parse(is);
// get the results - should be a fully populated RSSFeed instance, or null on error
return theRssHandler.getFeed();
}
catch (Exception ee)
{
// if we have a problem, simply return null
return null;
}
}
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
menu.add(0,0,0, "Choose RSS Feed");
menu.add(0,1,0, "Refresh");
Log.i(tag,"onCreateOptionsMenu");
return true;
}
public boolean onOptionsItemSelected(Menu item){
switch (((View) item).getId()) {
case 0:
Log.i(tag,"Set RSS Feed");
return true;
case 1:
Log.i(tag,"Refreshing RSS Feed");
return true;
}
return false;
}
private void UpdateDisplay()
{
TextView feedtitle = (TextView) findViewById(R.id.feedtitle);
TextView feedpubdate = (TextView) findViewById(R.id.feedpubdate);
ListView itemlist = (ListView) findViewById(R.id.itemlist);
if (feed == null)
{
feedtitle.setText("No RSS Feed Available");
return;
}
feedtitle.setText(feed.getTitle());
feedpubdate.setText(feed.getPubDate());
ArrayAdapter<RSSItem> adapter = new ArrayAdapter<RSSItem>(this,android.R.layout.simple_list_item_1,feed.getAllItems());
itemlist.setAdapter(adapter);
itemlist.setOnItemClickListener(this);
itemlist.setSelection(0);
}
public void onItemClick(AdapterView parent, View v, int position, long id)
{
Log.i(tag,"item clicked! [" + feed.getItem(position).getTitle() + "]");
Intent itemintent = new Intent(this,ShowDescription.class);
Bundle b = new Bundle();
b.putString("title", feed.getItem(position).getTitle());
b.putString("description", feed.getItem(position).getDescription());
b.putString("link", feed.getItem(position).getLink());
b.putString("pubdate", feed.getItem(position).getPubDate());
itemintent.putExtra("android.intent.extra.INTENT", b);
startSubActivity(itemintent,0);
}
private void startSubActivity(Intent itemintent, int i) {
// TODO Auto-generated method stub
}
}
This is my first approach to RSS Reader, It's no so dynamic and has boilerplate code but worked well for myself.
Usage:
RssParser parser = new RssParser(feedUrl);
Log.i("LOG", "Description: " + parser.getItem(3).description); //4th item's description
Class:
package com.uncocoder.course.app.feed_reader;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
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.util.Log;
public class RssParser extends DefaultHandler {
private StringBuilder content;
private boolean inChannel;
private boolean inImage;
private boolean inItem;
private ArrayList<Item> items = new ArrayList<Item>();
private Channel channel = new Channel();
private Item lastItem;
public RssParser(String url) {
try {
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
URL sourceUrl = new URL(url);
xr.setContentHandler(this);
xr.parse(new InputSource(sourceUrl.openStream()));
}
catch (ParserConfigurationException e) {
e.printStackTrace();
}
catch (SAXException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
public class Item {
public String title;
public String description;
public String link;
public String category;
public String pubDate;
public String guid;
}
public class Channel {
public String title;
public String description;
public String link;
public String lastBuildDate;
public String generator;
public String imageUrl;
public String imageTitle;
public String imageLink;
public String imageWidth;
public String imageHeight;
public String imageDescription;
public String language;
public String copyright;
public String pubDate;
public String category;
public String ttl;
}
#Override
public void startDocument() throws SAXException {
Log.i("LOG", "StartDocument");
}
#Override
public void endDocument() throws SAXException {
Log.i("LOG", "EndDocument");
}
#Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
if (localName.equalsIgnoreCase("image")) {
inImage = true;
}
if (localName.equalsIgnoreCase("channel")) {
inChannel = true;
}
if (localName.equalsIgnoreCase("item")) {
lastItem = new Item();
items.add(lastItem);
inItem = true;
}
content = new StringBuilder();
}
#Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (localName.equalsIgnoreCase("image")) {
inImage = false;
}
if (localName.equalsIgnoreCase("channel")) {
inChannel = false;
}
if (localName.equalsIgnoreCase("item")) {
inItem = false;
}
if (localName.equalsIgnoreCase("title")) {
if (content == null) {
return;
}
if (inItem) {
lastItem.title = content.toString();
} else if (inImage) {
channel.imageTitle = content.toString();
} else if (inChannel) {
channel.title = content.toString();
}
content = null;
}
if (localName.equalsIgnoreCase("description")) {
if (content == null) {
return;
}
if (inItem) {
lastItem.description = content.toString();
} else if (inImage) {
channel.imageDescription = content.toString();
} else if (inChannel) {
channel.description = content.toString();
}
content = null;
}
if (localName.equalsIgnoreCase("link")) {
if (content == null) {
return;
}
if (inItem) {
lastItem.link = content.toString();
} else if (inImage) {
channel.imageLink = content.toString();
} else if (inChannel) {
channel.link = content.toString();
}
content = null;
}
if (localName.equalsIgnoreCase("category")) {
if (content == null) {
return;
}
if (inItem) {
lastItem.category = content.toString();
} else if (inChannel) {
channel.category = content.toString();
}
content = null;
}
if (localName.equalsIgnoreCase("pubDate")) {
if (content == null) {
return;
}
if (inItem) {
lastItem.pubDate = content.toString();
} else if (inChannel) {
channel.pubDate = content.toString();
}
content = null;
}
if (localName.equalsIgnoreCase("guid")) {
if (content == null) {
return;
}
lastItem.guid = content.toString();
content = null;
}
if (localName.equalsIgnoreCase("url")) {
if (content == null) {
return;
}
channel.imageUrl = content.toString();
content = null;
}
if (localName.equalsIgnoreCase("width")) {
if (content == null) {
return;
}
channel.imageWidth = content.toString();
content = null;
}
if (localName.equalsIgnoreCase("height")) {
if (content == null) {
return;
}
channel.imageHeight = content.toString();
content = null;
}
if (localName.equalsIgnoreCase("language")) {
if (content == null) {
return;
}
channel.language = content.toString();
content = null;
}
if (localName.equalsIgnoreCase("copyright")) {
if (content == null) {
return;
}
channel.copyright = content.toString();
content = null;
}
if (localName.equalsIgnoreCase("ttl")) {
if (content == null) {
return;
}
channel.ttl = content.toString();
content = null;
}
}
#Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (content == null) {
return;
}
content.append(ch, start, length);
}
public Item getItem(int index) {
return items.get(index);
}
}
Check following link, It's open source RSS reader for Android, You can download code for reference
http://code.google.com/p/android-rss/
There is a tutorial (including complete source code) on how to build an Android RSS reder here:
part 1 (complete application)
part 2 (application updated to parse image tags from desciption)
part 3 (application update with Android 3.0)
The tutorial uses SAX parser and includes a complete Android project that accesses an RSS feed and then displays the feed in a list view.
There still seems to be a lot of people interested in this - so if you are looking for an Android 3.0+ with fragments/async tasks etc, as well as complete application code, I have updated the posts again, and they can be found here!
You can download and check my project on google-play.
This project is about some turkish sport channels feeds. Lots of channels are in one application.
You can check source code of project on github.
Parse this type of Rss Feeds easily using XmlPullParser
public class RSSParser {
public static ArrayList<Pojo> getParserData(String Data){
try {
RSSXMLTag currentTag = null;
ArrayList<Pojo> postDataList = new ArrayList<>();
XmlPullParserFactory factory = XmlPullParserFactory
.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(new StringReader(Data));
int eventType = xpp.getEventType();
Pojo pdData = null;
SimpleDateFormat dateFormat = new SimpleDateFormat(
"EEEE, DD MMM yyyy ");
while (eventType != XmlPullParser.END_DOCUMENT) {
int i = 0;
if (eventType == XmlPullParser.START_DOCUMENT) {
} else if (eventType == XmlPullParser.START_TAG) {
if (xpp.getName().equals("item")) {
pdData = new Pojo();
currentTag = RSSXMLTag.IGNORETAG;
} else if (xpp.getName().equals("title")) {
currentTag = RSSXMLTag.TITLE;
} else if (xpp.getName().equals("link")) {
currentTag = RSSXMLTag.LINK;
} else if (xpp.getName().equals("pubDate")) {
currentTag = RSSXMLTag.DATE;
} else if (xpp.getName().equals("creator")) {
currentTag = RSSXMLTag.CREATOR;
} else if (xpp.getName().equals("category")) {
currentTag = RSSXMLTag.CATEGORY;
} else if (xpp.getName().equals("description")) {
currentTag = RSSXMLTag.DESCRIPTION;
}
} else if (eventType == XmlPullParser.END_TAG) {
if (xpp.getName().equals("item")) {
// format the data here, otherwise format data in
// Adapter
Date postDate = dateFormat.parse(pdData.postDate);
pdData.postDate = dateFormat.format(postDate);
postDataList.add(pdData);
} else {
currentTag = RSSXMLTag.IGNORETAG;
}
} else if (eventType == XmlPullParser.TEXT) {
String content = xpp.getText();
content = content.trim();
Log.d("debug", content);
if (pdData != null) {
switch (currentTag) {
case TITLE:
if (content.length() != 0) {
if (pdData.postTitle != null) {
pdData.postTitle += content;
} else {
pdData.postTitle = content;
}
}
break;
case LINK:
if (content.length() != 0) {
if (pdData.postLink != null) {
pdData.postLink += content;
} else {
pdData.postLink = content;
}
}
break;
case DATE:
if (content.length() != 0) {
if (pdData.postDate != null) {
pdData.postDate += content;
} else {
pdData.postDate = content;
}
}
break;
case CATEGORY:
if (content.length() != 0) {
if (pdData.postCategory != null) {
i = i + 1;
if (i == 1) {
pdData.postCategory = content;
}
} else {
i = i + 1;
if (i == 1) {
pdData.postCategory = content;
}
}
}
break;
case DESCRIPTION:
if (content.length() != 0) {
if (pdData.postDescription != null) {
String s = content;
String string = s.substring(s.indexOf("src=\"") + 5, s.indexOf("\" class=\""));
pdData.postDescription += string;
} else {
String s = content;
String string = s.substring(s.indexOf("src=\"") + 5, s.indexOf("\" class=\""));
pdData.postDescription = string;
}
}
break;
case CREATOR:
if (content.length() != 0) {
if (pdData.postCreator != null) {
pdData.postCreator += content;
} else {
pdData.postCreator = content;
}
}
break;
default:
break;
}
}
}
eventType = xpp.next();
}
return postDataList;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
public enum RSSXMLTag {
IGNORETAG, TITLE, LINK, DATE,CREATOR,CATEGORY, DESCRIPTION;
}
public class Pojo {
public String getPostTitle() {
return postTitle;
}
public void setPostTitle(String postTitle) {
this.postTitle = postTitle;
}
public String getPostLink() {
return postLink;
}
public void setPostLink(String postLink) {
this.postLink = postLink;
}
public String getPostDate() {
return postDate;
}
public void setPostDate(String postDate) {
this.postDate = postDate;
}
public String getPostCategory() {
return postCategory;
}
public void setPostCategory(String postCategory) {
this.postCategory = postCategory;
}
public String getPostDescription() {
return postDescription;
}
public void setPostDescription(String postDescription) {
this.postDescription = postDescription;
}
public String getPostCreator() {
return postCreator;
}
public void setPostCreator(String postCreator) {
this.postCreator = postCreator;
}
public String postTitle;
public String postLink;
public String postDate;
public String postCategory;
public String postDescription;
public String postCreator;
}
}