问题
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();
}
}
}
回答1:
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")
回答2:
Answer
I fixed my problem if anyone is interested you can read that question.
回答3:
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
来源:https://stackoverflow.com/questions/21551352/how-do-i-use-asynctask-on-a-parser