문제

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();
        }
    }
}
도움이 되었습니까?

해결책 2

Answer

I fixed my problem if anyone is interested you can read that question.

다른 팁

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")

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

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top