android - 适配器的内容已经改变但是ListView没有收到通知

标签 android android-listview android-asynctask

我得到这个错误: java.lang.IllegalStateException: 适配器的内容已更改但 ListView 未收到通知。确保你的适配器的内容不是从后台线程修改的,而只是从 UI 线程修改的。 [在 ListView(2131034188, class android.widget.ListView) with Adapter(class .MainActivity$ListAdapter)]

这就是我所做的,我运行一个 AsyncTask 并获取 json 数据,然后,在 PostExecute 上,我调用 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 就构建好了。我在几个不同的设备上测试过它,没有一个有任何问题,但一些用户告诉我,我登录并看到这个错误。

我应该怎么做才能解决?怎么了 ?

谢谢你

最佳答案

对于迟来的回复深表歉意,但它在我之前的评论中似乎是可疑的:您正在从两个不同的线程修改 contactList

ListView 缓存元素计数,每当它必须对其子项进行布局时,它会再次检查此计数与绑定(bind)适配器中的当前项目数。如果计数已更改并且未通知 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() + ")]");
}

Source .

换句话说:这正是您遇到的错误。在您的场景中,计数差异是由多个线程修改支持数据集引起的,从而导致同步问题:后台线程可能会修改数据集,被挂起,然后 ui 线程可能会调用 layoutChildren () 而未收到有关数据集更改的通知。

现在,进入解决方案。最简单的方法是确保您没有修改绑定(bind)到来自不同线程的 ListView 适配器的列表。也就是说,要么制作一份您可以自由修改的副本,要么分配一个新列表。

所以,做这样的事情,即在 AsyncTaskonPreExecute() 方法中。

新列表:

List<HashMap<String, String>> mNewContactList = new ArrayList<HashMap<String, String>>();

(浅)副本:

List<HashMap<String, String>> mNewContactList = new ArrayList<HashMap<String, String>>(contactList);

然后,在doInBackground()中,将数据添加到mNewContactList。最后,在 onPostExecute() 中,您可以:

  1. 使用 mNewContactList 创建一个新适配器并将其设置到 ListView
  2. 或者(如果您没有复制原始列表)将 mNewContactList 的内容添加到已经存在的 contactList 并调用 notifyDatasetChanged() ListView 上。

关于android - 适配器的内容已经改变但是ListView没有收到通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26521683/

相关文章:

android - Android 上的 GStreamer x264enc 和 SIGSEGV

android - 图像不适合 QuickContactBadge

android - 如何在填充列表后以编程方式更改列表元素的高度

android - 如何在 youtube 播放器的 ListView 中显示视频?

java - 尝试通过 JSON 查询从 openweathermap 获取数据时获取 FileNotFoundException

java - 如果您有多个应用程序,则为 android 包名称

java - android中的json解析给出类型不匹配

android - 同一个asynctask可以被调用多次吗

java - Android 中的线程等待

android - 如何使应用程序响应所有 Android 设备?