Android, ListView IllegalStateException: "The content of the adapter has changed but ListView did not receive a notification"
I had the same issue.
I was adding items to my ArrayList
outside the UI thread.
Solution: I have done both, adding the items
and called notifyDataSetChanged()
in the UI thread.
I had the same problem, but I fixed it using the method
requestLayout();
from the class ListView
This is a MultiThreading Issue and Using Properly Synchronized Blocks This can be prevented. Without putting extra things on UI Thread and causing loss of responsiveness of app.
I also faced the same. And as the most accepted answer suggests making change to adapter data from UI Thread can solve the issue. That will work but is a quick and easy solution but not the best one.
As you can see for a normal case. Updating data adapter from background thread and calling notifyDataSetChanged in UI thread works.
This illegalStateException arises when a ui thread is updating the view and another background thread changes the data again. That moment causes this issue.
So if you will synchronize all the code which is changing the adapter data and making notifydatasetchange call. This issue should be gone. As gone for me and i am still updating the data from background thread.
Here is my case specific code for others to refer.
My loader on the main screen loads the phone book contacts into my data sources in the background.
@Override
public Void loadInBackground() {
Log.v(TAG, "Init loadings contacts");
synchronized (SingleTonProvider.getInstance()) {
PhoneBookManager.preparePhoneBookContacts(getContext());
}
}
This PhoneBookManager.getPhoneBookContacts reads contact from phonebook and fills them in the hashmaps. Which is directly usable for List Adapters to draw list.
There is a button on my screen. That opens a activity where these phone numbers are listed. If i directly setAdapter over the list before the previous thread finishes its work which is fast naviagtion case happens less often. It pops up the exception .Which is title of this SO question. So i have to do something like this in the second activity.
My loader in the second activity waits for first thread to complete. Till it shows a progress bar. Check the loadInBackground of both the loaders.
Then it creates the adapter and deliver it to the activity where on ui thread i call setAdapter.
That solved my issue.
This code is a snippet only. You need to change it to compile well for you.
@Override
public Loader<PhoneBookContactAdapter> onCreateLoader(int arg0, Bundle arg1) {
return new PhoneBookContactLoader(this);
}
@Override
public void onLoadFinished(Loader<PhoneBookContactAdapter> arg0, PhoneBookContactAdapter arg1) {
contactList.setAdapter(adapter = arg1);
}
/*
* AsyncLoader to load phonebook and notify the list once done.
*/
private static class PhoneBookContactLoader extends AsyncTaskLoader<PhoneBookContactAdapter> {
private PhoneBookContactAdapter adapter;
public PhoneBookContactLoader(Context context) {
super(context);
}
@Override
public PhoneBookContactAdapter loadInBackground() {
synchronized (SingleTonProvider.getInstance()) {
return adapter = new PhoneBookContactAdapter(getContext());
}
}
}
Hope this helps