What I want to do: run a background thread which calculates ListView contents and update ListView partially, while results are calculated.
W
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 solved this by have 2 Lists. One list I use for only the adapter, and I do all data changes/updates on the other list. This allows me to do updates on one list in a background thread, and then update the "adapter" list in the main/UI thread:
List<> data = new ArrayList<>();
List<> adapterData = new ArrayList();
...
adapter = new Adapter(adapterData);
listView.setAdapter(adapter);
// Whenever data needs to be updated, it can be done in a separate thread
void updateDataAsync()
{
new Thread(new Runnable()
{
@Override
public void run()
{
// Make updates the "data" list.
...
// Update your adapter.
refreshList();
}
}).start();
}
void refreshList()
{
runOnUiThread(new Runnable()
{
@Override
public void run()
{
adapterData.clear();
adapterData.addAll(data);
adapter.notifyDataSetChanged();
listView.invalidateViews();
}
});
}
i haved same problem when add new data in lazy image loader i just put
adapter.notifyDataSetChanged();
in
protected void onPostExecute(Void args) {
adapter.notifyDataSetChanged();
// Close the progressdialog
mProgressDialog.dismiss();
}
hope it helps you
Several days ago I met the same problem and causes several thousands of crash per day, about 0.1% of users meet this situation. I tried setVisibility(GONE/VISIBLE)
and requestLayout()
, but crash count only decreases a little.
And I finally solved it. Nothing with setVisibility(GONE/VISIBLE)
. Nothing with requestLayout()
.
Finally I found the reason is I used a Handler
to call notifyDataSetChanged()
after update data, which may lead to a sort of:
checkForTap()
/onTouchEvent()
and finally calls layoutChildren()
)notifyDataSetChanged()
and update viewsAnd I made another mistake that in getCount()
, getItem()
and getView()
, I directly use fields in DataSource, rather than copy them to the adapter. So finally it crashes when:
getCount()
and getView()
is called, and listview finds data is not consistent, and throws exceptions like java.lang.IllegalStateException: The content of the adapter has changed but...
. Another common exception is an IndexOutOfBoundException
if you use header/footer in ListView
.So solution is easy, I just copy data to adapter from my DataSource when my Handler triggers adapter to get data and calls notifyDataSetChanged()
. The crash now never happens again.
Please try one of these solutions :
Sometimes, if you add new object to data list in a thread (or doInBackground
method), this error will occur. The solution is : create a temporary list and do adding data to this list in thread(or doInBackground
), then do copying all data from temporary list to the list of adapter in UI thread (or onPostExcute
)
Make sure all UI updates are called in UI thread.
i had the same problem. finally i got the solution
before updating listview, if the soft keypad is present close it first. after that set data source and call notifydatasetchanged().
while closing keypad internally listview will update its ui. it keep calling till closing keypad. that time if data source change it willl throw this exception. if data is updating in onActivityResult, there is a chance for same error.
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
view.postDelayed(new Runnable() {
@Override
public void run() {
refreshList();
}
},100L);