Question

Here I am getting error while i click on generated list.

Here is my stack trace.

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. [in ListView(2131034118, class android.widget.ListView) with Adapter(class android.widget.SimpleAdapter)]

This is intitializing code;

ArrayList<HashMap<String, String>> rssItemList = new ArrayList<HashMap<String, String>>();
List<RSSItem> rssItems = new ArrayList<RSSItem>();
RSSItem rssItem;
RSSParser rssParser = new RSSParser();

And this is my class which gives error.

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        rssItemList.clear();
    }

    @Override
    protected String doInBackground(String... args) {
        String url = args[0];
        rssItems = rssParser.getRSSFeedItems(url);
        // updating UI from Background Thread
        runOnUiThread(new Runnable() {
            public void run() {
                FeedDBHandler rssDb = new FeedDBHandler(
                        getApplicationContext());
                // RSSItem rssItem;
                rssItems.size();
                Log.i("size", "size:" + rssItems.size());
                if (rssItems != null) {
                    for (RSSItem item : rssItems) {
                        // creating new HashMap
                        HashMap<String, String> map = new HashMap<String, String>();

                        // Truncating description
                        String description = item.getDescription();
                        if (description.length() > 100)
                            description = description.substring(3, 97)
                                    + "..";

                        // Store in database
                        rssItem = new RSSItem(item.getTitle(),
                                item.getLink(), item.getCategory(),
                                description, item.getPubdate());

                        // check if not exist -notify and insert
                        if (!rssDb.isExistItem(item.getLink())) {
                            createNotification(item.getTitle());
                            rssDb.addFeed(rssItem);
                        }
                        createNotification(item.getTitle());
                        if (map != null) {
                            map.put(TAG_TITLE, item.getTitle());
                            map.put(TAG_LINK, item.getLink());
                            map.put(TAG_CATEGORY, item.getCategory());
                            map.put(TAG_DESRIPTION, description);
                            map.put(TAG_PUB_DATE, item.getPubdate());
                        }

                        rssItemList.add(map);
                    }
                }

                /**
                 * Updating parsed items into listview
                 * */
                // runOnUiThread(new Runnable() {
                // public void run() {
                // adding HashList to ArrayList
                ListAdapter adapter = new SimpleAdapter(
                        AndroidRSSReaderList.this, rssItemList,
                        R.layout.rss_item_list_row, new String[] {
                                TAG_LINK, TAG_TITLE, TAG_DESRIPTION,
                                TAG_PUB_DATE }, new int[] { R.id.page_url,
                                R.id.title, R.id.link, R.id.pub_date });

                // updating listview
                lv.setAdapter(adapter);
                // registerForContextMenu(lv);
                // setListAdapter(adapter);
            }
        });
        return null;
    }

    @Override
    protected void onPostExecute(String result) {
        // dismiss the dialog after getting all products
        // pDialog.dismiss();
        runOnUiThread(new Runnable() {
            public void run() {
                if (rssItem != null) {

                }
            }
        });
    }

This is my AsyncTask Class.

Was it helpful?

Solution 2

AsyncTask is used to execute code NOT in the main (UI) thread. What you are doing is executing the fetch code in the UI thread and trying to set the adapter in a background thread. So first read this and then you can try to move your code around like this:

@Override
protected void onPreExecute() {
    super.onPreExecute();
    rssItemList.clear();
}

@Override
protected String doInBackground(String... args) {
    String url = args[0];
    rssItems = rssParser.getRSSFeedItems(url);
    FeedDBHandler rssDb = new FeedDBHandler(
            getApplicationContext());
    // RSSItem rssItem;
    rssItems.size();
    Log.i("size", "size:" + rssItems.size());

    if (rssItems != null) {
        for (RSSItem item : rssItems) {
            // creating new HashMap
            HashMap<String, String> map = new HashMap<String, String>();

            // Truncating description
            String description = item.getDescription();
            if (description.length() > 100)
                description = description.substring(3, 97)
                        + "..";

            // Store in database
            rssItem = new RSSItem(item.getTitle(),
                    item.getLink(), item.getCategory(),
                    description, item.getPubdate());

            // check if not exist -notify and insert
            if (!rssDb.isExistItem(item.getLink())) {
                createNotification(item.getTitle());
                rssDb.addFeed(rssItem);
            }
            createNotification(item.getTitle());
            if (map != null) {
                map.put(TAG_TITLE, item.getTitle());
                map.put(TAG_LINK, item.getLink());
                map.put(TAG_CATEGORY, item.getCategory());
                map.put(TAG_DESRIPTION, description);
                map.put(TAG_PUB_DATE, item.getPubdate());
            }

            rssItemList.add(map);                


        }
    });

    return rssItemList;
}

@Override
protected void onPostExecute(ArrayList<HashMap<String, String>> rssItemList) {
    ListAdapter adapter = new SimpleAdapter(
    AndroidRSSReaderList.this, rssItemList,
    R.layout.rss_item_list_row, new String[] {
                TAG_LINK, TAG_TITLE, TAG_DESRIPTION,
                TAG_PUB_DATE }, new int[] { R.id.page_url,
                R.id.title, R.id.link, R.id.pub_date });

    // updating listview
    lv.setAdapter(adapter);
    // when updating the adapter call
    // adapter.notifyDataSetChanged();


    // dismiss the dialog after getting all products
    pDialog.dismiss();

}

OTHER TIPS

You should set list adapter in postexecute method, and Activity should not recreated by orientation change or screen off.

You should always make any updates to your views on the UI thread, otherwise you risk errors such as these. The statement:

lv.setAdapter(adapter);

...is an update to your ListView and fails because doInBackground is not running on the main thread. Badoniya is correct in his suggestion to use the postexecute method of your AsyncTask because that method does run on the UI thread.

This also applies if you ever subsequently update the underlying dataset of your adapter after binding it it a view. Any changes you make, plus the subsequent call to notifyDataSetChanged(), must be on the UI thread.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top