Search This Blog

Tuesday 13 March 2012

IllegalStateException: The content of the adapter has changed but ListView did not receive a notification

This is very common problem when we are updating listview's adapter value Let me try to explain what is happening here - When you create a with an Adapter backing it up, the ListView gets its data by asking the adapter for it. Every time you scroll, the ListView is asking the Adapter for the new items that you scrolled into.
Normally you create the ListView, you create the Adapter, you set the adapter on the listview, and you are done. Android OS takes care of the rest. What you are attempting to do, however, is a bit more complicated. You are trying to occasionally update the data in the adapter. You can imagine that the listview would need to be informed if the adapter data changed, right? If you are displaying a list with 2 items, and you suddenly add 2 more items to the adapter, then the list should now be displaying 4 items! However, it would be really inefficient if the listview had to be continually checking to see if the adapter has changed, right? So what needs to happen is the listview will assume that the adapter doesn't change, and the adapter will notify the listview if it does change. (This agreement between the listview and the adapter allows other benefits, such as the listview can cache some of the items retrieved from the adapter for quick access. Aka if there are 10 list items displayed on the screen, the list may have actually already requested 14 items. That way if you scroll up or down, for at least 2 items in either direction the ListView already has the data to display!)


What you have failed to do, however, is to notify the listview that the data inside of the adapter changed.

So one solution for this problem is to call method listAdapter.notifyDataSetChanged();


this solution is not full proof yet.

I have gone through stack overflow and Google group so i am combining all solution may any of them help you

1)By Jerry Fan     
 I have a fix for this. Just set the visibility of your List View to Gone during
 update and back to visible after update. By doing so, u can avoid the
 inconsistency of your adapter and ListView item count.

2)Almost work in each case listAdapter.notifyDataSetChanged();

Now code how to use these

public class ListViewStressTest extends ListActivity {
    ArrayAdapter<String> adapter;
    ListView list;
    AsyncTask<Void, String, Void> task;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
        this.list = this.getListView();
        this.list.setAdapter(this.adapter);
        this.task = new AsyncTask<Void, String, Void>() {
            Random r = new Random();
            int[] delete;
            volatile boolean scroll = false;
            @Override
            protected void onProgressUpdate(String... values) {
                if(scroll) {
                    scroll = false;
                    doScroll();
                    return;
                }
                if(values == null) {
                    doDelete();
                    return;
                }
                doUpdate(values);
                if(ListViewStressTest.this.adapter.getCount() > 5000) {
                    ListViewStressTest.this.adapter.clear();
                }
            }
            private void doScroll() {
                if(ListViewStressTest.this.adapter.getCount() == 0) {
                    return;
                }

                int n = r.nextInt(ListViewStressTest.this.adapter.getCount());
                ListViewStressTest.this.list.setSelection(n);
            }

            private void doDelete() {
                int[] d;
                synchronized(this) {
                    d = this.delete;
                }
                if(d == null) {
                    return;
                }
                for(int i = 0 ; i < d.length ; i++) {
                    int index = d[i];
                    if(index >= 0 && index < ListViewStressTest.this.adapter.getCount()) {
                        ListViewStressTest.this.adapter.remove(ListViewStressTest.this.adapter.getItem(index));
                    }
                }
            }

            private void doUpdate(String... values) {
                for(int i = 0 ; i < values.length ; i++) {
                    ListViewStressTest.this.adapter.add(values[i]);
                }
            }

            private void updateList() {
                int number = r.nextInt(30) + 1;
                String[] strings = new String[number];

                for(int i = 0 ; i < number ; i++) {
                    strings[i] = Long.toString(r.nextLong());
                }

                this.publishProgress(strings);
            }

            private void deleteFromList() {
                int number = r.nextInt(20) + 1;
                int[] toDelete = new int[number];

                for(int i = 0 ; i < number ; i++) {
                    int num = ListViewStressTest.this.adapter.getCount();
                    if(num < 2) {
                        break;
                    }
                    toDelete[i] = r.nextInt(num);
                }

                synchronized(this) {
                    this.delete = toDelete;
                }

                this.publishProgress(null);
            }

            private void scrollSomewhere() {
                this.scroll = true;
                this.publishProgress(null);
            }

            @Override
            protected Void doInBackground(Void... params) {
                while(true) {
                    int what = r.nextInt(3);

                    switch(what) {
                        case 0:
                            updateList();
                            break;
                        case 1:
                            deleteFromList();
                            break;
                        case 2:
                            scrollSomewhere();
                            break;
                    }

                    try {
                        Thread.sleep(0);
                    } catch(InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }

        };

        this.task.execute(null);
    }
}



Article Similar to this

No comments:

Post a Comment

Feedback always help in improvement. If you have any query suggestion feel free to comment and Keep visiting my blog to encourage me to blogging

Android News and source code