Mistaken Mistaken - 24 days ago 5
Android Question

java.lang.IllegalStateException: The content of the adapter has changed but ListView.... inspite of calling notifydatasetchanged()

What are the best practices to be followed to update the contents of a listactivty by a background thread (Async Task) ?

1) Am calling the notifyDataSetChanged() to update the adapter as soon as i manipulate the contents of the adapter but still my app force closes while the user scrolls or click on the list. Any pointers to prevent this would be very helpfull.

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

2) Where exaclty should i update contents of the listactivity ? inside the doInBackground() or onProgressUpdate()?

3) Am experiencing regular crashes when the user clicks the list item. So will disabling click events on the listactivty during the background operation solve the problem ? If so am not sure how to remove or set item click listeners dynamically to the listactivity. Please instruct me on the too.

4) I dont think blocking all ui interactions during the background async task execution is the only way to solve the problem. I know there is a simple way of doing this but need some help.

Thanks in advance.

This is my onCreate...

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fa);

tvStatus=(TextView) findViewById(R.id.tvStatus);

adapter = new SimpleAdapter(
this,
mostPopularList,
R.layout.list_item,
new String[] {"title","author","views","date"},
new int[] {R.id.textView1,R.id.textView2,R.id.textView4,R.id.textView3});
//populateList();


setListAdapter(adapter);
}


My async task...

private class LongOperation extends AsyncTask<String, Void, String> {

@Override
protected String doInBackground(String... params) {
// code for adding new listactivty items
}

@Override
protected void onPostExecute(String networkStatus) {
adapter.notifyDataSetChanged();
}

@Override
protected void onPreExecute() {

}

@Override
protected void onProgressUpdate(Void... values) {

}
}


Logcat:

i rarely the the illegalstate exception too... not able to reproduce it. will post the logcat if i come across it again.

FATAL EXCEPTION: main
java.lang.IndexOutOfBoundsException: Invalid index 7, size is 4
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:257)
at java.util.ArrayList.get(ArrayList.java:311)
at android.widget.SimpleAdapter.bindView(SimpleAdapter.java:147)
at android.widget.SimpleAdapter.createViewFromResource(SimpleAdapter.java:126)
at android.widget.SimpleAdapter.getView(SimpleAdapter.java:114)
at android.widget.AbsListView.obtainView(AbsListView.java:1294)
at android.widget.ListView.makeAndAddView(ListView.java:1727)
at android.widget.ListView.fillDown(ListView.java:652)
at android.widget.ListView.fillGap(ListView.java:623)
at android.widget.AbsListView.trackMotionScroll(AbsListView.java:2944)
at android.widget.AbsListView.onTouchEvent(AbsListView.java:2065)
at android.widget.ListView.onTouchEvent(ListView.java:3315)
at android.view.View.dispatchTouchEvent(View.java:3766)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:897)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1671)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1107)
at android.app.Activity.dispatchTouchEvent(Activity.java:2086)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1655)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1671)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1107)
at android.app.Activity.dispatchTouchEvent(Activity.java:2086)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1655)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1785)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4627)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)

Answer

2) Where exaclty should i update contents of the listactivity ? inside the doInBackground() or onProgressUpdate()?

Inside onProgressUpdate() or inside onPostExecute() because it could take some time since you change content in doInBackground() and call async task calls your

          @Override
          protected void onPostExecute(String networkStatus) {
            adapter.notifyDataSetChanged();
          }

3) Am experiencing regular crashes when the user clicks the list item. So will disabling click events on the listactivty during the background operation solve the problem ? If so am not sure how to remove or set item click listeners dynamically to the listactivity. Please instruct me on the too.

It is not a solution. You just need update your dataset on UI thread. (Not load content, just update from old to a new one). For example

private class LongOperation extends AsyncTask<String, Void, String> {

      @Override
      protected List<String> doInBackground(String... params) {
           List<String> items = loadUpdatedDataset(params);
           return items;
      }      

      @Override
      protected void onPostExecute(List<String> loadedItems) {
        updateAdapterDataset(loadedItems);
        adapter.notifyDataSetChanged();
      }

      @Override
      protected void onPreExecute() {

      }

      @Override
      protected void onProgressUpdate(Void... values) {

       }
      }