ListView displaying incorrect title - android

I have a simple application that pulls an XML file from pc worlds RSS feed here:
http://feeds.pcworld.com/pcworld/latestnews
I want to display the name of the titles in a ListView then when the user selects one the article opens up in a browser window.
The application is working the only thing is that the title is not being displayed correctly in the ListView.
It should be something like this:
Make you website stand out with Windows 8
But instead it is this:
com.example.simplerss.Item#424b9998
Any ideas?
This is my code for the MainActivity
public class MainActivity extends ListActivity {
ArrayAdapter<Item> adapter;
List<Item>items;//Holds item objects containing info relating to element pulled from XML file.
Item item;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//initialize variables
items = new ArrayList<Item>();
new PostTask().execute();
adapter= new ArrayAdapter<Item>(this, android.R.layout.simple_list_item_1, items);
setListAdapter(adapter);
}
private InputStream getInputStream(URL url) {
try{
return url.openConnection().getInputStream();
}catch(IOException e){
return null;
}
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Uri uri = items.get(position).getLink();
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
//ASYNC CLASS
private class PostTask extends AsyncTask<String, Integer, String>{
#Override
protected String doInBackground(String... arg0) {
try{
//link to data source
URL url = new URL("http://feeds.pcworld.com/pcworld/latestnews");
//Set up parser
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(false);
XmlPullParser xpp = factory.newPullParser();
//get XML from input stream
InputStream in = getInputStream(url);
if (in == null) {
throw new Exception("Empty inputstream");
}
xpp.setInput(in, "UTF_8");
//Keep track of which tag inside of XML
boolean insideItem = false;
//Loop through the XML file and extract data required
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
Log.v("ENTER", String.valueOf(xpp.getEventType()));
if (xpp.getName().equalsIgnoreCase("item")) {
insideItem = true;
//Create new item object
item = new Item();
} else if (xpp.getName().equalsIgnoreCase("title")) {
if (insideItem){
item.setTitle(xpp.nextText());
Log.i("title", item.getTitle());
}
}
else if (xpp.getName().equalsIgnoreCase("description")) {
if (insideItem){
item.setDescription(xpp.nextText());
}
}
else if (xpp.getName().equalsIgnoreCase("link")) {
if (insideItem){
item.setLink(Uri.parse(xpp.nextText()));
}
}
}else if(eventType==XmlPullParser.END_TAG && xpp.getName().equalsIgnoreCase("item")){
insideItem=false;
//add item to list
items.add(item);
}
eventType = xpp.next(); //move to next element
publishProgress();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
return "COMPLETED";
}
#Override
protected void onProgressUpdate(Integer... values) {
adapter.notifyDataSetChanged();
}
public void onPostExecute(String s) {
Toast.makeText(getApplicationContext(), s + " Items: " + items.size(), Toast.LENGTH_SHORT).show();
adapter.notifyDataSetChanged();
}
}
}
and for the Item Class
public class Item {
//Variables
private String title;
private Uri link;
private String description;
public Item() {
super();
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Uri getLink() {
return link;
}
public void setLink(Uri link) {
this.link = link;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

Override the toString() method in Item.
#Override
public String toString() {
return title;
}
This should solve your problem.
Right now, the ArrayAdapter sets its View's texts to Item.toString(), but this is the default method of Object that returns the Object's ID. With overriding it, you give it a meaningful value, in your case the title.

I think the problem lies in:
else if (xpp.getName().equalsIgnoreCase("title")) {
if (insideItem){
item.setTitle(xpp.nextText());
Log.i("title", item.getTitle());
}
}
Here, getName() is a method from the Java Class object. The method you want is readContent() I think. I haven't used this library so that may not be exactly correct but you can certainly find what you need in the docs.

Related

Displaying xml float data

I am trying to create an earthquake watcher app but I can't seem to get the coordinates and other sections from the XML URL to show on my activity when I load the project I know that they are of type float. I have tried different methods and I have no errors on the console so it must be something with the way that I am calling it??
I have added some output and images
package ja.example.mpd1starterearth;
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
ListView lvRss;
ArrayList<String> titles;
ArrayList<String> links;
ArrayList<Double> lat;
ArrayList<Double> lon;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lvRss = (ListView) findViewById(R.id.lvRss);
titles = new ArrayList<String>();
links = new ArrayList<String>();
lat = new ArrayList<Double>();
lon = new ArrayList<Double>();
lvRss.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Uri uri = Uri.parse(links.get(position));
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
});
new ProcessInBackground().execute();
}
public InputStream getInputStream(URL url)
{
try
{
//openConnection() returns instance that represents a connection to the remote object referred to by the URL
//getInputStream() returns a stream that reads from the open connection
return url.openConnection().getInputStream();
}
catch (IOException e)
{
return null;
}
}
public class ProcessInBackground extends AsyncTask<Integer, Void, Exception>
{
ProgressDialog progressDialog = new ProgressDialog(MainActivity.this);
Exception exception = null;
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog.setMessage("Busy loading rss feed...please wait...");
progressDialog.show();
}
#Override
protected Exception doInBackground(Integer... params) {
try
{
URL url = new URL("http://quakes.bgs.ac.uk/feeds/MhSeismology.xml");
//creates new instance of PullParserFactory that can be used to create XML pull parsers
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
//Specifies whether the parser produced by this factory will provide support
//for XML namespaces
factory.setNamespaceAware(false);
//creates a new instance of a XML pull parser using the currently configured
//factory features
XmlPullParser xpp = factory.newPullParser();
// We will get the XML from an input stream
xpp.setInput(getInputStream(url), "UTF_8");
/* We will parse the XML content looking for the "<title>" tag which appears inside the "<item>" tag.
* We should take into consideration that the rss feed name is also enclosed in a "<title>" tag.
* Every feed begins with these lines: "<channel><title>Feed_Name</title> etc."
* We should skip the "<title>" tag which is a child of "<channel>" tag,
* and take into consideration only the "<title>" tag which is a child of the "<item>" tag
*
* In order to achieve this, we will make use of a boolean variable called "insideItem".
*/
boolean insideItem = false;
// Returns the type of current event: START_TAG, END_TAG, START_DOCUMENT, END_DOCUMENT etc..
int eventType = xpp.getEventType(); //loop control variable
while (eventType != XmlPullParser.END_DOCUMENT)
{
//if we are at a START_TAG (opening tag)
if (eventType == XmlPullParser.START_TAG)
{
//if the tag is called "item"
if (xpp.getName().equalsIgnoreCase("item"))
{
insideItem = true;
}
//if the tag is called "title"
else if (xpp.getName().equalsIgnoreCase("title"))
{
if (insideItem)
{
// extract the text between <title> and </title>
titles.add(xpp.nextText());
}
}
//if the tag is called "link"
else if (xpp.getName().equalsIgnoreCase("link"))
{
if (insideItem)
{
// extract the text between <link> and </link>
links.add(xpp.nextText());
}
}
else if(xpp.getName().equalsIgnoreCase("geo:lat")){
if(insideItem){
//extract the text between <geo:lat> and </geo:lat>
lat.add(Double.valueOf(xpp.nextText()));
}
}
else if(xpp.getName().equalsIgnoreCase("geo:long")){
if(insideItem) {
//extract the text between <geo:lat> and </geo:lat>
lon.add(Double.valueOf(xpp.nextText()));;
} }
}
//if we are at an END_TAG and the END_TAG is called "item"
else if (eventType == XmlPullParser.END_TAG && xpp.getName().equalsIgnoreCase("item"))
{
insideItem = false;
}
eventType = xpp.next(); //move to next element
}
}
catch (MalformedURLException e)
{
exception = e;
}
catch (XmlPullParserException e)
{
exception = e;
}
catch (IOException e)
{
exception = e;
}
return exception;
}
#Override
protected void onPostExecute(Exception s) {
super.onPostExecute(s);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, titles);
lvRss.setAdapter(adapter);
progressDialog.dismiss();
}
}
}
Your code to parse data from the URL is totally correct. You do not see all data all the activity because this line of code.
ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, titles);
You pass titles arraylist to the adapter, that why you only see all title xml value in the activity.
Solution: The simple way is format the data which connect from 4 array list titles, links, lat, lon.
/**
* This method will format data from titles, links, lat, lon arraylist.
*/
private List<String> formatDataBeforeDisplayOnListView(){
List<String> list = new ArrayList<>();
StringBuilder sb = new StringBuilder();
int size = titles.size();
for (int i = 0; i < size; ++i) {
String title = titles.get(i);
String link = links.get(i);
Double geoLat = lat.get(i);
Double getLon = lon.get(i);
sb.append("title: ").append(title).append("\n")
.append("link: ").append(link).append("\n")
.append("geo-lat: ").append(geoLat).append("\n")
.append("geo-lon: ").append(getLon);
list.add(sb.toString());
}
return list;
}
Then change your code to
// Comment-out this line
// ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, titles);
List<String> items = formatDataBeforeDisplayOnListView();
ArrayAdapter<String> adapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_list_item_1, items);
Note: If you want to display each item listview in a better design/UI then you should write a custom adapter class instead of ArrayAdapter.
Updated: Based on Jase's comment
First, declare a new class named Item
public class Item {
private String title;
private String link;
private Double lat;
private Double lon;
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;
}
public Double getLat() {
return lat;
}
public void setLat(Double lat) {
this.lat = lat;
}
public Double getLon() {
return lon;
}
public void setLon(Double lon) {
this.lon = lon;
}
#Override
public String toString() {
return (new StringBuilder()).append("title: ").append(title).append("\n")
.append("link: ").append(link).append("\n")
.append("geo-lat: ").append(lat).append("\n")
.append("geo-lon: ").append(lon).toString();
}
}
Then, change your activity code to
public class MainActivity extends AppCompatActivity {
ListView lvRss;
ArrayList<Item> mItems = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lvRss = (ListView) findViewById(R.id.lvRss);
lvRss.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// TODO: Process clicked item here
Item item = (Item) parent.getItemAtPosition(position);
Uri uri = Uri.parse(item.getLink());
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
});
new ProcessInBackground().execute();
}
public InputStream getInputStream(URL url) {
try {
//openConnection() returns instance that represents a connection to the remote object referred to by the URL
//getInputStream() returns a stream that reads from the open connection
return url.openConnection().getInputStream();
} catch (IOException e) {
return null;
}
}
public class ProcessInBackground extends AsyncTask<Integer, Void, Exception> {
ProgressDialog progressDialog = new ProgressDialog(MainActivity.this);
Exception exception = null;
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog.setMessage("Busy loading rss feed...please wait...");
progressDialog.show();
}
#Override
protected Exception doInBackground(Integer... params) {
try {
URL url = new URL("http://quakes.bgs.ac.uk/feeds/MhSeismology.xml");
//creates new instance of PullParserFactory that can be used to create XML pull parsers
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
//Specifies whether the parser produced by this factory will provide support
//for XML namespaces
factory.setNamespaceAware(false);
//creates a new instance of a XML pull parser using the currently configured
//factory features
XmlPullParser xpp = factory.newPullParser();
// We will get the XML from an input stream
xpp.setInput(getInputStream(url), "UTF_8");
/* We will parse the XML content looking for the "<title>" tag which appears inside the "<item>" tag.
* We should take into consideration that the rss feed name is also enclosed in a "<title>" tag.
* Every feed begins with these lines: "<channel><title>Feed_Name</title> etc."
* We should skip the "<title>" tag which is a child of "<channel>" tag,
* and take into consideration only the "<title>" tag which is a child of the "<item>" tag
*
* In order to achieve this, we will make use of a boolean variable called "insideItem".
*/
boolean insideItem = false;
// Returns the type of current event: START_TAG, END_TAG, START_DOCUMENT, END_DOCUMENT etc..
int eventType = xpp.getEventType(); //loop control variable
Item item = null;
while (eventType != XmlPullParser.END_DOCUMENT) {
//if we are at a START_TAG (opening tag)
if (eventType == XmlPullParser.START_TAG) {
//if the tag is called "item"
if (xpp.getName().equalsIgnoreCase("item")) {
insideItem = true;
item = new Item();
}
//if the tag is called "title"
else if (xpp.getName().equalsIgnoreCase("title")) {
if (insideItem) {
// extract the text between <title> and </title>
item.setTitle(xpp.nextText());
}
}
//if the tag is called "link"
else if (xpp.getName().equalsIgnoreCase("link")) {
if (insideItem) {
// extract the text between <link> and </link>
item.setLink(xpp.nextText());
}
} else if (xpp.getName().equalsIgnoreCase("geo:lat")) {
if (insideItem) {
//extract the text between <geo:lat> and </geo:lat>
item.setLat(Double.valueOf(xpp.nextText()));
}
} else if (xpp.getName().equalsIgnoreCase("geo:long")) {
if (insideItem) {
//extract the text between <geo:lat> and </geo:lat>
item.setLon(Double.valueOf(xpp.nextText()));
}
}
}
//if we are at an END_TAG and the END_TAG is called "item"
else if (eventType == XmlPullParser.END_TAG && xpp.getName().equalsIgnoreCase("item")) {
insideItem = false;
mItems.add(item);
}
eventType = xpp.next(); //move to next element
}
} catch (MalformedURLException e) {
exception = e;
} catch (XmlPullParserException e) {
exception = e;
} catch (IOException e) {
exception = e;
}
return exception;
}
#Override
protected void onPostExecute(Exception s) {
super.onPostExecute(s);
ArrayAdapter<Item> adapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_list_item_1, mItems);
lvRss.setAdapter(adapter);
progressDialog.dismiss();
}
}
}
You are comparing tag name with space in it thus equalsIgnoreCase() will always return false as geo:lang will not be equal to geo :lat.
Just test this code.
String s = "geo:lang";
System.out.println(""+s.equalsIgnoreCase("geo :long"));
You need to remove space in between o and : for both cases eg.equalsIgnoreCase("geo:long")

How to get URL from each ListView item

I have a ListView that generates roughly 20 article titles. Everything works except that every ListView item takes me to the same URL. I'm trying to figure out how I can access every URL since it's instantiated inside a nested class. The URI is parsed in my setOnItemClickListener:
First, the Article class:
public class Article {
private String link;
public Article() {
}
public Article(String link) {
this.link = link;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
#Override
public String toString() {
return this.link;
}
}
Then the Activity:
public class NewsActivity extends AppCompatActivity {
ListView mListView;
Document document;
Elements newsFeed;
Elements links;
String href;
private static final String TAG = "NewsActivity";
private ArrayList<Article> mArticleList = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_news);
HtmlParser htmlThread = new HtmlParser();
htmlThread.execute();
mListView = findViewById(R.id.articleListView);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//THE PROBLEM IS THAT EVERY ITEM GOES TO THE SAME URL
Uri uri = Uri.parse(href);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
});
}
public class HtmlParser extends AsyncTask<Void, Integer, ArrayList<Article>> {
private static final int NETWORK_NO_ERROR = -1;
private static final int NETWORK_HOST_UNREACHABLE = 1;
private static final int NETWORK_NO_ACCESS_TO_INTERNET = 2;
private static final int NETWORK_TIME_OUT = 3;
Integer serverError = NETWORK_NO_ERROR;
ProgressDialog dialog;
protected void onPreExecute() {
dialog = new ProgressDialog(NewsActivity.this);
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dialog.setMessage("Retrieving News Feed");
dialog.show();
}
#Override
protected ArrayList<Article> doInBackground(Void... params) {
try {
document = Jsoup.connect("my_url_here").get();
//get news and titles
newsFeed = document.getElementsByClass("the_element_class");
//get links
links = newsFeed.select("a[href]");
for(Element link : links) {
mArticleList.add(new Article(link.text()));
href = links.attr("href"); //tried to get all of the links here
}
return mArticleList;
} catch(ConnectException e) {
serverError = NETWORK_NO_ACCESS_TO_INTERNET;
return null;
} catch (UnknownHostException e) {
serverError = NETWORK_HOST_UNREACHABLE;
return null;
} catch(SocketTimeoutException e) {
serverError = NETWORK_TIME_OUT;
return null;
} catch (IOException e) {
e.printStackTrace();
}
return null;
} //end doInBackground
protected void onProgressUpdate(Integer... progress) {
} // end onProgressUpdate
protected void onPostExecute(ArrayList<Article> result) {
if(result != null) {
ListView listView = findViewById(R.id.articleListView);
listView.setAdapter(new ArrayAdapter<Article>(NewsActivity.this, R.layout.custom_textview, mArticleList));
if(dialog.isShowing()) {
dialog.dismiss();
}
} else {
switch(serverError) {
case NETWORK_NO_ERROR:
Toast.makeText(NewsActivity.this, "Oops. Invalid response from server.", Toast.LENGTH_LONG).show();
break;
case NETWORK_NO_ACCESS_TO_INTERNET:
Toast.makeText(NewsActivity.this, "No Internet connection found.", Toast.LENGTH_SHORT).show();
break;
case NETWORK_TIME_OUT:
case NETWORK_HOST_UNREACHABLE:
Toast.makeText(NewsActivity.this, "Error in connection.", Toast.LENGTH_LONG).show();
break;
}
}
}
}
}

Get more information in arraylist

I'm developing an Android application for read some information from a XML file on the web. At first, I had a problem to parsing. Now my problem is that my code read only one information. I've created my class MyFilm. How can I insert all information from that file in my arraylist. Thank you in advance.
public class FilmListActivity extends ListActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new WebService() {
#Override
protected ArrayList<MyFilm> doInBackground(Object... params) {
ArrayList<MyFilm> arr = new ArrayList<MyFilm>();
Intent intent = getIntent();
String pkg = getPackageName();
try {
MyFilm parametriRicerca = new MyFilm();
parametriRicerca = (MyFilm) intent.getSerializableExtra(pkg+".MyFilm");
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
URL input = new URL("http://whatdowedo.altervista.org/griffith_list2.xml");
xpp.setInput(input.openStream(), null);
int eventType = xpp.getEventType();
String currentTag = null;
MyFilm tmp = new MyFilm();
String title = null;
String regista = null;
String attore = null;
String genere = null;
String paese = null;
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
currentTag = xpp.getName();
} else if (eventType == XmlPullParser.TEXT) {
if ("title".equals(currentTag)) {
title = xpp.getText().trim();
}
if("director".equals(currentTag)){
regista = xpp.getText().trim();
}
if("country".equals(currentTag)){
paese = xpp.getText().trim();
}
if("genre".equals(currentTag)){
genere = xpp.getText().trim();
}
if("cast".equals(currentTag)){
attore = xpp.getText().trim();
}
if(parametriRicerca.getTitle().equals(title)){
arr.add(parametriRicerca);
}
}
eventType = xpp.next();
}
} catch (Exception e) {
e.printStackTrace();
}
return arr;
}
}.execute();
}
abstract class WebService extends AsyncTask<Object, MyFilm, ArrayList<MyFilm>> {
public WebService() {
super();
}
#Override
protected void onPreExecute() {
}
#Override
protected abstract ArrayList<MyFilm> doInBackground(Object... params);
#Override
protected void onPostExecute(ArrayList<MyFilm> result) {
super.onPostExecute(result);
FilmsAdapterView adapter = new FilmsAdapterView(FilmListActivity.this,result);
setListAdapter(adapter);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}

How do I use AsyncTask on a parser? [duplicate]

This question already has an answer here:
java.lang.StackOverflowError trying to parse in a AsyncTask
(1 answer)
Closed 8 years ago.
I have been reading this tutorial and came across the problem that it uses a very low api. I got the NetworkOnMainThreadException. I found this answer on stackoverflow which says I have to use AsyncTask.
I have tried using AsyncTask on an empty project working with another tutorial which worked fine.
My problem is that I need to change this project so that I can use it on higher apis. So the thing is AndroidSaxFeedParser is a subclass and AsyncTask is a super class and the error line is on AndroidSaxFeedParser which extends BaseFeedParser and BaseFeedParser extends FeedParser which is an interface(btw I always thought interfaces had to be implemented instead of extended?).
To be more precise the errors are on these line(indicated with --->) :
AndroidSaxFeedParser.java :
try
{
---> Xml.parse(this.getInputStream(), Xml.Encoding.UTF_8, root.getContentHandler());
}
catch (Exception e)
{
---> throw new RuntimeException(e);
}
MessageList.java :
private void loadFeed(ParserType type)
{
try
{
Log.i("AndroidNews", "ParserType=" + type.name());
FeedParser parser = FeedParserFactory.getParser(type);
long start = System.currentTimeMillis();
---> messages = parser.parse();
long duration = System.currentTimeMillis() - start;
Log.i("AndroidNews", "Parser duration=" + duration);
String xml = writeXml();
Log.i("AndroidNews", xml);
List<String> titles = new ArrayList<String>(messages.size());
for (Message msg : messages)
{
titles.add(msg.getTitle());
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.row, titles);
this.setListAdapter(adapter);
}
catch (Throwable t)
{
Log.e("AndroidNews", t.getMessage(), t);
}
}
BaseFeedParser.java :
protected InputStream getInputStream()
{
try
{
---> return feedUrl.openConnection().getInputStream();
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
So where and how should I use the AsyncTask. (I'm only using the AndroidSaxParser so the other parsers in the tutorial can be ignored).
AndroidSaxFeedParser.java
public class AndroidSaxFeedParser extends BaseFeedParser
{
static final String RSS = "rss";
public AndroidSaxFeedParser(String feedUrl)
{
super(feedUrl);
}
public List<Message> parse()
{
final Message currentMessage = new Message();
RootElement root = new RootElement(RSS);
final List<Message> messages = new ArrayList<Message>();
Element channel = root.getChild(CHANNEL);
Element item = channel.getChild(ITEM);
item.setEndElementListener(new EndElementListener()
{
public void end()
{
messages.add(currentMessage.copy());
}
});
item.getChild(TITLE).setEndTextElementListener(new EndTextElementListener()
{
public void end(String body)
{
currentMessage.setTitle(body);
}
});
item.getChild(LINK).setEndTextElementListener(new EndTextElementListener()
{
public void end(String body)
{
currentMessage.setLink(body);
}
});
item.getChild(DESCRIPTION).setEndTextElementListener(new EndTextElementListener()
{
public void end(String body)
{
currentMessage.setDescription(body);
}
});
item.getChild(PUB_DATE).setEndTextElementListener(new EndTextElementListener()
{
public void end(String body)
{
currentMessage.setDate(body);
}
});
try
{
Xml.parse(this.getInputStream(), Xml.Encoding.UTF_8, root.getContentHandler());
}
catch (Exception e)
{
throw new RuntimeException(e);
}
return messages;
}
}
BaseFeedParser.java
public abstract 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";
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);
}
}
}
FeedParser.java
public interface FeedParser
{
List<Message> parse();
}
FeedParserFactory.java
public abstract class FeedParserFactory
{
static String feedUrl = "http://example.com/feed/";
public static FeedParser getParser()
{
return getParser(ParserType.ANDROID_SAX);
}
public static FeedParser getParser(ParserType type)
{
switch (type)
{
case SAX:
return new SaxFeedParser(feedUrl);
case DOM:
return new DomFeedParser(feedUrl);
case ANDROID_SAX:
return new AndroidSaxFeedParser(feedUrl);
case XML_PULL:
return new XmlPullFeedParser(feedUrl);
default:
return null;
}
}
}
Message.java
public class Message implements Comparable<Message>
{
static SimpleDateFormat FORMATTER = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss Z", Locale.ENGLISH);
private String title;
private URL link;
private String description;
private Date date;
public String getTitle()
{
return title;
}
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;
return copy;
}
#Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("Title: ");
sb.append(title);
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;
return true;
}
public int compareTo(Message another)
{
if (another == null)
return 1;
// sort descending, most recent first
return another.date.compareTo(date);
}
}
MessageList.java
public class MessageList extends ListActivity
{
private List<Message> messages;
#Override
public void onCreate(Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.main);
loadFeed(ParserType.ANDROID_SAX);
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
menu.add(Menu.NONE, ParserType.ANDROID_SAX.ordinal(), ParserType.ANDROID_SAX.ordinal(), R.string.android_sax);
menu.add(Menu.NONE, ParserType.SAX.ordinal(), ParserType.SAX.ordinal(), R.string.sax);
menu.add(Menu.NONE, ParserType.DOM.ordinal(), ParserType.DOM.ordinal(), R.string.dom);
menu.add(Menu.NONE, ParserType.XML_PULL.ordinal(), ParserType.XML_PULL.ordinal(), R.string.pull);
return true;
}
#SuppressWarnings("unchecked")
#Override
public boolean onMenuItemSelected(int featureId, MenuItem item)
{
super.onMenuItemSelected(featureId, item);
ParserType type = ParserType.values()[item.getItemId()];
ArrayAdapter<String> adapter = (ArrayAdapter<String>) this.getListAdapter();
if (adapter.getCount() > 0)
{
adapter.clear();
}
this.loadFeed(type);
return true;
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id)
{
super.onListItemClick(l, v, position, id);
Intent viewMessage = new Intent(Intent.ACTION_VIEW, Uri.parse(messages.get(position).getLink().toExternalForm()));
this.startActivity(viewMessage);
}
private void loadFeed(ParserType type)
{
try
{
Log.i("AndroidNews", "ParserType=" + type.name());
FeedParser parser = FeedParserFactory.getParser(type);
long start = System.currentTimeMillis();
messages = parser.parse();
long duration = System.currentTimeMillis() - start;
Log.i("AndroidNews", "Parser duration=" + duration);
String xml = writeXml();
Log.i("AndroidNews", xml);
List<String> titles = new ArrayList<String>(messages.size());
for (Message msg : messages)
{
titles.add(msg.getTitle());
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.row, titles);
this.setListAdapter(adapter);
}
catch (Throwable t)
{
Log.e("AndroidNews", t.getMessage(), t);
}
}
private String writeXml()
{
XmlSerializer serializer = Xml.newSerializer();
StringWriter writer = new StringWriter();
try
{
serializer.setOutput(writer);
serializer.startDocument("UTF-8", true);
serializer.startTag("", "messages");
serializer.attribute("", "number", String.valueOf(messages.size()));
for (Message msg : messages)
{
serializer.startTag("", "message");
serializer.attribute("", "date", msg.getDate());
serializer.startTag("", "title");
serializer.text(msg.getTitle());
serializer.endTag("", "title");
serializer.startTag("", "url");
serializer.text(msg.getLink().toExternalForm());
serializer.endTag("", "url");
serializer.startTag("", "body");
serializer.text(msg.getDescription());
serializer.endTag("", "body");
serializer.endTag("", "message");
}
serializer.endTag("", "messages");
serializer.endDocument();
return writer.toString();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
ParserType.java
public enum ParserType
{
SAX, DOM, ANDROID_SAX, XML_PULL;
}
RssHandler.java
public class RssHandler extends DefaultHandler
{
private List<Message> messages;
private Message currentMessage;
private StringBuilder builder;
public List<Message> getMessages()
{
return this.messages;
}
#Override
public void characters(char[] ch, int start, int length) throws SAXException
{
super.characters(ch, start, length);
builder.append(ch, start, length);
}
#Override
public void endElement(String uri, String localName, String name) throws SAXException
{
super.endElement(uri, localName, name);
if (this.currentMessage != null)
{
if (localName.equalsIgnoreCase(TITLE))
{
currentMessage.setTitle(builder.toString());
}
else if (localName.equalsIgnoreCase(LINK))
{
currentMessage.setLink(builder.toString());
}
else if (localName.equalsIgnoreCase(DESCRIPTION))
{
currentMessage.setDescription(builder.toString());
}
else if (localName.equalsIgnoreCase(PUB_DATE))
{
currentMessage.setDate(builder.toString());
}
else if (localName.equalsIgnoreCase(ITEM))
{
messages.add(currentMessage);
}
builder.setLength(0);
}
}
#Override
public void startDocument() throws SAXException
{
super.startDocument();
messages = new ArrayList<Message>();
builder = new StringBuilder();
}
#Override
public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException
{
super.startElement(uri, localName, name, attributes);
if (localName.equalsIgnoreCase(ITEM))
{
this.currentMessage = new Message();
}
}
}
public class ParseAsync extends AsyncTask<Url, Void, ArrayList<FeedItem>> {
#Override
protected ArrayList<FeedItem> doInBackground(Url... params) {
//url as parametr, long time operation
return YourParser.parseFeed(params[0])
}
#Override
protected void onPostExecute(ArrayList<FeedItem> result) {
// this we get result of parser in ui thread
}
}
In ui thread
ParseAsync task = new ParseAsync();
task.execute("www.example.ru/feed.rss")
Answer
I fixed my problem if anyone is interested you can read that question.
i think the problem is because of NetworkOnMainThreadException,So what you want to do is that you need to add StrictMode
Where you use the Async task,so just add this linke on preexectue of the async task
int SDK_INT = android.os.Build.VERSION.SDK_INT;
if (SDK_INT>8){
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
Hope this will solve your problem

How to parse local xml file to get country details android?

i have to parse xml file to get country details like country name and country postal code.
how can i parse country names to spinner adapter and when i select perticular country using spinner i have to display particular country code in textview.
please help me.
Thanks in advance.
Here is a code to parse Xml file where you will have to pass inputstream of your local xml file.
public static ArrayList<Country> parseCountry(Context context, InputStream inputStream) {
String KEY = "";
String VALUE = null;
ArrayList<Country> arrCountires = new ArrayList<Country>();
Country country = null;
ArrayList<State> arrStates = null;
State state= null;
ArrayList<City> arrCities = null;
City city = null;
try {
InputStreamReader inputreader = null;
if(inputStream != null) {
inputreader = new InputStreamReader(inputStream);
}
if(inputreader != null) {
XmlPullParserFactory factory = null;
factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = null;
xpp = factory.newPullParser();
xpp.setInput(inputreader);
int eventType = 0;
eventType = xpp.getEventType();
eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if(eventType == XmlPullParser.START_TAG) {
KEY = xpp.getName();
if(KEY.equalsIgnoreCase(TAGS.COUNTRIES)) {
arrCountires = new ArrayList<Country>();
}else if(KEY.equalsIgnoreCase(TAGS.COUNTRY)) {
country = new Country();
arrStates = new ArrayList<State>();
country.setCountryId(xpp.getAttributeValue(null, TAGS.ID));
}else if(KEY.equalsIgnoreCase(TAGS.STATE)) {
state = new State();
arrCities = new ArrayList<City>();
state.setStateId(xpp.getAttributeValue(null, TAGS.ID));
}else if(KEY.equalsIgnoreCase(TAGS.CITY)) {
city = new City();
city.setCityId(xpp.getAttributeValue(null, TAGS.ID));
}
}else if(eventType == XmlPullParser.END_TAG) {
KEY = xpp.getName();
if(KEY.equalsIgnoreCase(TAGS.COUNTRY)) {
country.setArrStates(arrStates);
arrCountires.add(country);
}else if(KEY.equalsIgnoreCase(TAGS.COUNTRY_NAME)) {
country.setCountryName(VALUE);
}else if(KEY.equalsIgnoreCase(TAGS.STATE_NAME)) {
state.setStateName(VALUE);
}else if(KEY.equalsIgnoreCase(TAGS.STATE)) {
state.setArrCities(arrCities);
arrStates.add(state);
}else if(KEY.equalsIgnoreCase(TAGS.CITY)) {
arrCities.add(city);
}else if(KEY.equalsIgnoreCase(TAGS.CITY_NAME)) {
city.setCityName(VALUE);
}
}else if(eventType == XmlPullParser.TEXT) {
VALUE = xpp.getText();
}
eventType = xpp.next();
}
}
}
catch (Exception e) {
e.printStackTrace();
}finally {
if(inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return arrCountires;
}
Here is a Country class with Getter and Setter methods.
public class Country {
String countryId;
String countryName;
ArrayList<State> arrStates;
public ArrayList<State> getArrStates() {
return arrStates;
}
public void setArrStates(ArrayList<State> arrStates) {
this.arrStates = arrStates;
}
public String getCountryId() {
return countryId;
}
public void setCountryId(String countryId) {
this.countryId = countryId;
}
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
}
Here is a Adapter class to set country in the spinner.
private class CountryAdapter implements SpinnerAdapter{
ArrayList<Country> data;
public CountryAdapter(ArrayList<Country> data){
this.data = data;
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int position) {
return data.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return android.R.layout.simple_spinner_dropdown_item;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView v = new TextView(getApplicationContext());
v.setTextColor(Color.BLACK);
v.setText(data.get(position).getName());
v.setTextSize(15);
v.setPadding(10, 10, 10, 10);
v.setSingleLine();
v.setEllipsize(TruncateAt.END);
return v;
}
#Override
public int getViewTypeCount() {
return android.R.layout.simple_spinner_item;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isEmpty() {
return false;
}
#Override
public void registerDataSetObserver(DataSetObserver observer) {
}
#Override
public void unregisterDataSetObserver(DataSetObserver observer) {
}
#Override
public View getDropDownView(int position, View convertView,
ViewGroup parent) {
return this.getView(position, convertView, parent);
}
}
Here is a Interface by which you can get the selected country from the spinner
OnItemSelectedListener OnCountrySelected = new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View v, int position,
long id) {
if(position != AdapterView.INVALID_POSITION) {
System.out.println("Country name = " + arrCountries.get(position).getName());
//Here you can set this value to the textview
}
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
}
};
Here is a way how you can set the Listener to the spinner
spCountry.setOnItemSelectedListener(OnCountrySelected);
Here is a code to open file as inputstream from assets
try {
InputStream inputStream = v.getContext().getAssets().open("path of file");
ArrayList<Country> arrCountries = parseCountry(this, inputStream);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
When you get the response in the array of Country then set adapter to the spinner
CountryAdapter countryAdapter = new CountryAdapter(arrCountry);
spCountry.setAdapter(countryAdapter);

Categories

Resources