My app was reading RSS to an ArrayList called rssItems and what I was trying to do is to call the setDataSetChanged method of the adapter whenever a new item is added to the ArrayList. I also used AsyncTask to read the RSS from a different thread.

To do this, I passed the AsyncTask into the RssParseHandler as a parameter, so the handler can call the publishProgress method of the AsyncTask object whenever it finishes reading an RSS item. Since publishProgress is a protected method, I wrote a public wrapper method called publicPublishProgress so the handler can call it outside the AsyncTask object. Below is are some of my code:

public class MainActivity extends Activity {

private MainActivity local;
private List<RssItem> rssItems;
RssItemAdapter<RssItem> adapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    this.rssItems = new ArrayList<RssItem>();

    this.adapter = new RssItemAdapter<RssItem>(local,
            R.layout.rss_row_view, rssItems);

    // Get references to the Fragments
    FragmentManager fm = getFragmentManager();
    // find the fragment
    newsFragment newsFragment = (newsFragment) fm
            .findFragmentById(R.id.newsFragment);

    newsFragment.setListItems(rssItems);

    newsFragment.setListAdapter(adapter);


    GetRSSDataTask task = new GetRSSDataTask(this.rssItems, this.adapter, "blah.jpg");
    task.execute("http://somesite.net/category/news/feed/");

    Log.d("RssReader", Thread.currentThread().getName());
}

And this is the GetRSSDataTask extended from AsyncTask:

public class GetRSSDataTask extends AsyncTask<String, Void, Void> {

private String icon;
private RssReader rssReader;
private RssItemAdapter<RssItem> adapter;
private List<RssItem> rssItems;

public GetRSSDataTask(List<RssItem> rssItems, RssItemAdapter<RssItem> adapter, String icon) {
    super();
    this.icon = icon;
    this.adapter = adapter;
    this.rssItems = rssItems;
}

@Override
protected void onPreExecute() {

}

@Override
protected Void doInBackground(String... urls) {



    // Create a list adapter
    this.rssReader = new RssReader(urls[0], this.icon,
            this.rssItems, this);
    // Debug the task thread name
    Log.d("RssReader", Thread.currentThread().getName());

    try {

        // Parse RSS, get items
        rssReader.getItems();

    } catch (Exception e) {
        Log.e("RssReader", e.getMessage());
    }
    return null;
}

    // I created this method for the rss handler to access the publishProgress method.
public void publicPublishProgress(){
    publishProgress();
}

@Override
protected void onProgressUpdate(Void... values) {
            // update the UI
    this.adapter.notifyDataSetChanged();

}
@Override
protected void onPostExecute(Void result) {

}
}

This is the RssReader class:

public class RssReader {

private String rssUrl;
private String icon;
private List<RssItem> rssItems;
private GetRSSDataTask task;


public RssReader(String rssUrl, String icon, List<RssItem> rssItems, GetRSSDataTask task) {
    this.rssUrl = rssUrl;
    this.icon = icon;
    this.task = task;
}


public List<RssItem> getItems() throws Exception {
    SAXParserFactory factory = SAXParserFactory.newInstance();

    SAXParser saxParser = factory.newSAXParser();
    RssParseHandler handler = new RssParseHandler(this.icon, this.rssItems, this.task);
    saxParser.parse(rssUrl, handler);
    return handler.getItems();


}

}

And the RssParseHandler class:

public class RssParseHandler extends DefaultHandler {

private List<RssItem> rssItems;
// We have a local reference to an object which is constructed while parser is working on an item tag
// Used to reference item while parsing
private RssItem currentItem;
// We have two indicators which are used to differentiate whether a tag title or link is being processed by the parser
// Parsing title indicator
private boolean parsingTitle;
// Parsing link indicator
private boolean parsingLink;
private String icon;
private GetRSSDataTask task;

public RssParseHandler(String icon, List<RssItem> rssItems, GetRSSDataTask task) {
    this.rssItems = rssItems;
    this.task = task;
    this.icon = icon;
}

// We have an access method which returns a list of items that are read from the RSS feed. This method will be called when parsing is done.
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;
    }
}

// The EndElement method adds the  current RssItem to the list when a closing item tag is processed. It sets appropriate indicators to false -  when title and link closing tags are processed
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
    if ("item".equals(qName)) {
        currentItem.setIcon(this.icon);
        rssItems.add(currentItem);

        // update the progress
        this.task.publicPublishProgress();
        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;
        }
    }
}

}

Below are the error messages:

03-08 00:46:08.420: E/AndroidRuntime(1466): FATAL EXCEPTION: AsyncTask #1
03-08 00:46:08.420: E/AndroidRuntime(1466): Process: com.example.bucknellian, PID: 1466
03-08 00:46:08.420: E/AndroidRuntime(1466): java.lang.RuntimeException: An error occured while executing doInBackground()
03-08 00:46:08.420: E/AndroidRuntime(1466):     at android.os.AsyncTask$3.done(AsyncTask.java:300)
03-08 00:46:08.420: E/AndroidRuntime(1466):     at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
03-08 00:46:08.420: E/AndroidRuntime(1466):     at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
03-08 00:46:08.420: E/AndroidRuntime(1466):     at java.util.concurrent.FutureTask.run(FutureTask.java:242)
03-08 00:46:08.420: E/AndroidRuntime(1466):     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
03-08 00:46:08.420: E/AndroidRuntime(1466):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
03-08 00:46:08.420: E/AndroidRuntime(1466):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
03-08 00:46:08.420: E/AndroidRuntime(1466):     at java.lang.Thread.run(Thread.java:841)
03-08 00:46:08.420: E/AndroidRuntime(1466): Caused by: java.lang.NullPointerException: println needs a message
03-08 00:46:08.420: E/AndroidRuntime(1466):     at android.util.Log.println_native(Native Method)
03-08 00:46:08.420: E/AndroidRuntime(1466):     at android.util.Log.e(Log.java:232)
03-08 00:46:08.420: E/AndroidRuntime(1466):     at com.example.bucknellian.util.GetRSSDataTask.doInBackground(GetRSSDataTask.java:49)
03-08 00:46:08.420: E/AndroidRuntime(1466):     at com.example.bucknellian.util.GetRSSDataTask.doInBackground(GetRSSDataTask.java:1)
03-08 00:46:08.420: E/AndroidRuntime(1466):     at android.os.AsyncTask$2.call(AsyncTask.java:288)
03-08 00:46:08.420: E/AndroidRuntime(1466):     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
03-08 00:46:08.420: E/AndroidRuntime(1466):     ... 4 more
03-08 00:46:11.590: I/Process(1466): Sending signal. PID: 1466 SIG: 9

Any help is appreciated!!

After changing e.getMessage() to e.toString():

03-08 01:42:24.240: W/dalvikvm(826): threadid=11: thread exiting with uncaught exception (group=0xb3a32ba8)
03-08 01:42:24.300: E/AndroidRuntime(826): FATAL EXCEPTION: AsyncTask #1
03-08 01:42:24.300: E/AndroidRuntime(826): Process: com.example.bucknellian, PID: 826
03-08 01:42:24.300: E/AndroidRuntime(826): java.lang.RuntimeException: An error occured while executing doInBackground()
03-08 01:42:24.300: E/AndroidRuntime(826):  at android.os.AsyncTask$3.done(AsyncTask.java:300)
03-08 01:42:24.300: E/AndroidRuntime(826):  at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
03-08 01:42:24.300: E/AndroidRuntime(826):  at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
03-08 01:42:24.300: E/AndroidRuntime(826):  at java.util.concurrent.FutureTask.run(FutureTask.java:242)
03-08 01:42:24.300: E/AndroidRuntime(826):  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
03-08 01:42:24.300: E/AndroidRuntime(826):  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
03-08 01:42:24.300: E/AndroidRuntime(826):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
03-08 01:42:24.300: E/AndroidRuntime(826):  at java.lang.Thread.run(Thread.java:841)
03-08 01:42:24.300: E/AndroidRuntime(826): Caused by: java.lang.NullPointerException: println needs a message
03-08 01:42:24.300: E/AndroidRuntime(826):  at android.util.Log.println_native(Native Method)
03-08 01:42:24.300: E/AndroidRuntime(826):  at android.util.Log.e(Log.java:232)
03-08 01:42:24.300: E/AndroidRuntime(826):  at com.example.bucknellian.util.GetRSSDataTask.doInBackground(GetRSSDataTask.java:47)
03-08 01:42:24.300: E/AndroidRuntime(826):  at com.example.bucknellian.util.GetRSSDataTask.doInBackground(GetRSSDataTask.java:1)
03-08 01:42:24.300: E/AndroidRuntime(826):  at android.os.AsyncTask$2.call(AsyncTask.java:288)
03-08 01:42:24.300: E/AndroidRuntime(826):  at java.util.concurrent.FutureTask.run(FutureTask.java:237)
03-08 01:42:24.300: E/AndroidRuntime(826):  ... 4 more
03-08 01:42:36.100: D/dalvikvm(947): GC_FOR_ALLOC freed 70K, 5% free 3064K/3212K, paused 31ms, total 34ms
03-08 01:42:36.120: I/dalvikvm-heap(947): Grow heap (frag case) to 3.670MB for 635812-byte allocation
03-08 01:42:36.150: D/dalvikvm(947): GC_FOR_ALLOC freed 4K, 5% free 3680K/3836K, paused 28ms, total 28ms
03-08 01:42:36.230: D/RssReader(947): main
03-08 01:42:36.410: I/Choreographer(947): Skipped 32 frames!  The application may be doing too much work on its main thread.
03-08 01:42:36.470: D/gralloc_goldfish(947): Emulator without GPU emulation detected.
03-08 01:42:36.490: D/RssReader(947): AsyncTask #1
03-08 01:42:37.470: I/Choreographer(947): Skipped 36 frames!  The application may be doing too much work on its main thread.
03-08 01:42:40.100: E/RssReader(947): java.lang.NullPointerException

After changing to e.printStackTrace():

03-08 01:52:31.850: W/System.err(1201): java.lang.NullPointerException
03-08 01:52:31.850: W/System.err(1201):     at com.example.bucknellian.util.RssParseHandler.endElement(RssParseHandler.java:51)
03-08 01:52:31.850: W/System.err(1201):     at org.apache.harmony.xml.ExpatParser.endElement(ExpatParser.java:156)
03-08 01:52:31.860: W/System.err(1201):     at org.apache.harmony.xml.ExpatParser.appendBytes(Native Method)
03-08 01:52:31.860: W/System.err(1201):     at org.apache.harmony.xml.ExpatParser.parseFragment(ExpatParser.java:513)
03-08 01:52:31.860: W/System.err(1201):     at org.apache.harmony.xml.ExpatParser.parseDocument(ExpatParser.java:474)
03-08 01:52:31.860: W/System.err(1201):     at org.apache.harmony.xml.ExpatReader.parse(ExpatReader.java:316)
03-08 01:52:31.860: W/System.err(1201):     at org.apache.harmony.xml.ExpatReader.parse(ExpatReader.java:294)
03-08 01:52:31.860: W/System.err(1201):     at javax.xml.parsers.SAXParser.parse(SAXParser.java:390)
03-08 01:52:31.860: W/System.err(1201):     at javax.xml.parsers.SAXParser.parse(SAXParser.java:266)
03-08 01:52:31.860: W/System.err(1201):     at com.example.bucknellian.util.RssReader.getItems(RssReader.java:30)
03-08 01:52:31.860: W/System.err(1201):     at com.example.bucknellian.util.GetRSSDataTask.doInBackground(GetRSSDataTask.java:44)
03-08 01:52:31.860: W/System.err(1201):     at com.example.bucknellian.util.GetRSSDataTask.doInBackground(GetRSSDataTask.java:1)
03-08 01:52:31.860: W/System.err(1201):     at android.os.AsyncTask$2.call(AsyncTask.java:288)
03-08 01:52:31.860: W/System.err(1201):     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
03-08 01:52:31.860: W/System.err(1201):     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
03-08 01:52:31.860: W/System.err(1201):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
03-08 01:52:31.860: W/System.err(1201):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
03-08 01:52:31.860: W/System.err(1201):     at java.lang.Thread.run(Thread.java:841)

After adding rssItems to RssReader:

03-08 20:41:07.210: E/AndroidRuntime(1054): FATAL EXCEPTION: main
03-08 20:41:07.210: E/AndroidRuntime(1054): Process: com.example.bucknellian, PID: 1054
03-08 20:41:07.210: E/AndroidRuntime(1054): java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(16908298, class android.widget.ListView) with Adapter(class com.example.bucknellian.util.RssItemAdapter)]
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.widget.ListView.layoutChildren(ListView.java:1555)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.widget.AbsListView.onLayout(AbsListView.java:2091)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.View.layout(View.java:14817)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.ViewGroup.layout(ViewGroup.java:4631)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.View.layout(View.java:14817)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.ViewGroup.layout(ViewGroup.java:4631)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.View.layout(View.java:14817)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.ViewGroup.layout(ViewGroup.java:4631)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.View.layout(View.java:14817)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.ViewGroup.layout(ViewGroup.java:4631)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.View.layout(View.java:14817)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.ViewGroup.layout(ViewGroup.java:4631)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.View.layout(View.java:14817)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.ViewGroup.layout(ViewGroup.java:4631)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at com.android.internal.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:374)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.View.layout(View.java:14817)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.ViewGroup.layout(ViewGroup.java:4631)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.View.layout(View.java:14817)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.ViewGroup.layout(ViewGroup.java:4631)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:1987)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1744)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1000)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5670)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.Choreographer.doCallbacks(Choreographer.java:574)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.Choreographer.doFrame(Choreographer.java:544)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.os.Handler.handleCallback(Handler.java:733)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.os.Handler.dispatchMessage(Handler.java:95)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.os.Looper.loop(Looper.java:136)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at android.app.ActivityThread.main(ActivityThread.java:5017)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at java.lang.reflect.Method.invokeNative(Native Method)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at java.lang.reflect.Method.invoke(Method.java:515)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
03-08 20:41:07.210: E/AndroidRuntime(1054):     at dalvik.system.NativeStart.main(Native Method)

I know this is because I tried to change the UI in a thread different form the UI thread. Do you know how to change it?

有帮助吗?

解决方案

Try this..

Use .printStackTrace(); to view error message

try {

    // Parse RSS, get items
    rssReader.getItems();

} catch (Exception e) {
    e.printStackTrace();
}

EDIT:

Add this.rssItems = rssItems; in your RssReader.class

public RssReader(String rssUrl, String icon, List<RssItem> rssItems, GetRSSDataTask task) {
    this.rssUrl = rssUrl;
    this.icon = icon;
    this.task = task;
    this.rssItems = rssItems;
}

其他提示

Try making your return type of doInBackground to Boolean (make sure you change all "Void"s to "Boolean" then return Boolean.TRUE for success or Boolean.FALSE for failure. I'm not sure if this will fix the error or not but it's good practice to return something from doInBackground. Also make sure that none of your Log calls are logging null objects.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top