我一直在阅读this教程,并遇到了它使用非常低的api的问题。我收到了NetworkOnMainThreadException。我在stackoverflow上找到了这个答案,说我必须使用AsyncTask。
我尝试在一个空项目中使用AsyncTask,使用另一个工作正常的教程。
我的问题是我需要更改此项目,以便我可以在更高的api上使用它。所以问题是AndroidSaxFeedParser是一个子类,AsyncTask是一个超类,错误行在AndroidSaxFeedParser上,扩展了BaseFeedParser,BaseFeedParser扩展了FeedParser,这是一个接口(顺便说一句,我一直认为接口必须实现而不是扩展?)。
更准确地说,错误在这些行上(用--->表示): 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);
}
}
那么我应该在哪里以及如何使用AsyncTask。 (我只使用AndroidSaxParser,因此可以忽略教程中的其他解析器。)
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();
}
}
}
答案 0 :(得分:0)
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
}
}
在ui线程中
ParseAsync task = new ParseAsync();
task.execute("www.example.ru/feed.rss")
答案 1 :(得分:0)
我解决了我的问题,如果有人有兴趣,你可以阅读这个问题。
答案 2 :(得分:-1)
我认为问题是因为NetworkOnMainThreadException,所以你要做的是你需要添加StrictMode
在使用Async任务的地方,只需在异步任务的preexectue上添加此链接
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);
}
希望这能解决您的问题