我收到此错误: java.lang.IllegalStateException:适配器的内容已更改,但ListView未收到通知。确保不从后台线程修改适配器的内容,而只是从UI线程修改。 [在ListView(2131034188,类android.widget.ListView)中使用Adapter(类.MainActivity $ ListAdapter)]
这就是我所做的,我运行AsyncTask并获取json数据,然后,onPostExecute,我调用ListAdapter将数据转换为listview。
@Override
protected Void doInBackground(Void... arg0) {
Spots_tab1_json sh = new Spots_tab1_json();
String jsonStr = sh.makeServiceCall(url + page, Spots_tab1_json.GET);
if (jsonStr != null) {
JSONObject jsonObj = new JSONObject(jsonStr);
contacts = jsonObj.getJSONArray(TAG_CONTACTS);
for (int i = 0; i < contacts.length(); i++) {
JSONObject c = contacts.getJSONObject(i);
String onvan = new String(c.getString("onvan").getBytes("ISO-8859-1"), "UTF-8");
String id = new String(c.getString("id").getBytes("ISO-8859-1"), "UTF-8");
String dates = new String(c.getString("dates").getBytes("ISO-8859-1"), "UTF-8");
String price = new String(c.getString("gheymat").getBytes("ISO-8859-1"), "UTF-8");
HashMap<String, String> contact = new HashMap<String, String>();
contact.put("onvan", onvan);
contact.put("img", new String(c.getString("img").getBytes("ISO-8859-1"), "UTF-8"));
contactList.add(contact);
}
}
}
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if (!isCancelled() && goterr == false) {
final ListAdapter ladap=new ListAdapter(MainActivity.this, contactList);
lv.setAdapter(ladap);
runOnUiThread(new Runnable() {
public void run() {
ladap.notifyDataSetChanged();
}});
}
}
然后,我的listView被构建。我已经在几个不同的设备上测试了它,没有它们有任何问题,但有些用户告诉我,我登录并看到这个错误。
我该怎么做才能解决它?怎么了 ?
谢谢你
答案 0 :(得分:7)
对于迟来的回复道歉,但在我之前的评论中显示为怀疑:您正在从两个不同的主题修改contactList
。
ListView
缓存元素计数,每当必须布局子元素时,它将再次检查绑定适配器中当前项目数的计数。如果计数已更改且未通知ListView
,则会引发错误:
else if (mItemCount != mAdapter.getCount()) {
throw new 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. Make sure your adapter calls notifyDataSetChanged() "
+ "when its content changes. [in ListView(" + getId() + ", " + getClass()
+ ") with Adapter(" + mAdapter.getClass() + ")]");
}
换句话说:这正是你得到的错误。在您的方案中,计数差异是由多个线程修改后备数据集引起的,导致同步问题:后台线程可能会修改数据集,被挂起,然后ui线程可能会调用{{1}没有得到有关数据集更改的通知。
现在,解决方案。最简单的方法是确保您不从不同的线程修改绑定到layoutChildren()
的适配器的列表。也就是说,要么制作一个可以自由修改的副本,要么分配一个新的列表。
所以,做这样的事情,即在ListView
的{{1}}方法中。
新列表:
onPreExecute()
(浅)副本:
AsyncTask
然后,在List<HashMap<String, String>> mNewContactList = new ArrayList<HashMap<String, String>>();
中,将数据添加到List<HashMap<String, String>> mNewContactList = new ArrayList<HashMap<String, String>>(contactList);
。最后,在doInBackground()
中,您可以:
mNewContactList
创建新适配器并将其设置为onPostExecute()
。mNewContactList
的内容添加到现有ListView
并在mNewContactList
上致电contactList
答案 1 :(得分:0)
数据更新和您的适配器调用notifyDataSetChanged()必须在同一代码块中。 例如:
正确的情况:
List
错误的情况:
runOnUiThread(new Runnable() {
@Override
public void run() {
mSelectedImages.add(image);
mAdapter.notifyDataSetChanged();
}
});