Android, ListView IllegalStateException: «Содержимое адаптера изменилось, но ListView не получил уведомление» - PullRequest
184 голосов
/ 28 июня 2010

Что я хочу сделать : запустить фоновый поток, который вычисляет содержимое ListView и частично обновить ListView, пока рассчитываются результаты.

Чего я знаю, что мне следует избегать : я не могу связываться с содержимым ListAdapter из фонового потока, поэтому я унаследовал AsyncTask и опубликовал результат (добавление записей в адаптер) из onProgressUpdate.Мой адаптер использует ArrayList объектов результатов, все операции над этими массивами синхронизированы.

Исследования других людей : здесь есть очень ценные данные здесь .Я также страдал от почти ежедневных сбоев для группы из ~ 500 пользователей, и когда я добавил блок list.setVisibility(GONE)/trackList.setVisibility(VISIBLE) в onProgressUpdate, сбои уменьшились в 10 раз, но не исчезли.(это было предложено в ответ )

То, что я иногда получал : пожалуйста, обратите внимание, что это происходит очень редко (один раз в неделю для одного из пользователей 3.5k).Но я бы хотел полностью избавиться от этой ошибки.Вот частичная трассировка стека:

`java.lang.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. [in ListView(2131296334, class android.widget.ListView) with Adapter(class com.transportoid.Tracks.TrackListAdapter)]
at android.widget.ListView.layoutChildren(ListView.java:1432)
at android.widget.AbsListView.onTouchEvent(AbsListView.java:2062)
at android.widget.ListView.onTouchEvent(ListView.java:3234)
at android.view.View.dispatchTouchEvent(View.java:3709)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:852)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
[...]

Справка? Больше не нужна, см. Ниже

ЗАКЛЮЧИТЕЛЬНЫЙ ОТВЕТ: Как оказалось, я былвызывая notifyDataSetChanged каждые 5 вставок, чтобы избежать мерцания и внезапных изменений списка.Это не может быть сделано таким образом, всегда уведомляйте адаптер при изменении базового списка.Эта ошибка давно исчезла для меня.

Ответы [ 24 ]

0 голосов
/ 22 мая 2013

Пожалуйста, попробуйте одно из следующих решений:

  1. Иногда, если вы добавляете новый объект в список данных в потоке (или doInBackground метод), возникает эта ошибка.Решение: создать временный список и добавить данные в этот список в потоке (или doInBackground), затем скопировать все данные из временного списка в список адаптеров в потоке пользовательского интерфейса (или onPostExcute)

  2. Убедитесь, что все обновления пользовательского интерфейса вызываются в потоке пользовательского интерфейса.

0 голосов
/ 10 ноября 2017

У меня была такая же проблема. наконец я получил решение

перед обновлением списка, если имеется программная клавиатура, сначала закройте ее. после этого установите источник данных и вызовите notifydatasetchanged ().

при внутреннем закрытии клавиатуры listview обновит свой интерфейс. он продолжает звонить до закрытия клавиатуры. тогда, если источник данных изменится, он выдаст это исключение. если данные обновляются в onActivityResult, существует вероятность возникновения такой же ошибки.

 InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(v.getWindowToken(), 0);

        view.postDelayed(new Runnable() {
            @Override
            public void run() {
                refreshList();
            }
        },100L);
0 голосов
/ 16 декабря 2017

Мое решение:

1) создать temp ArrayList.

2) выполнить тяжелую работу (выборка строк sqlite, ...) в методе doInBackground и добавить элементы ввременный архиватор.

3) добавьте все элементы из временного архива в ваш список рассылки в методе onPostExecute.

note: вы можете удалить некоторые элементы из списка и удалить изsqlite database и, возможно, удалите некоторые файлы, связанные с элементами из sdcard, просто удалите элементы из базы данных, удалите связанные с ними файлы и добавьте их во временный массив в background thread.затем в UI thread удалите элементы, существующие в временном массиве из списка рассылки.

Надеюсь, это поможет.

0 голосов
/ 15 апреля 2015

Как @Mullins сказал "
Я добавил элементы и вызвал notifyDataSetChanged() в потоке пользовательского интерфейса, и я решил это. - Маллинс ".

В моем случае у меня есть asynctask, и я вызвал notifyDataSetChanged() в методе doInBackground(), и проблема была решена, когда я позвонил с onPostExecute(), я получил исключение.

...