Android: IllegalStateException – Когда оно выбрано?

В моем приложении иногда возникает следующее исключение:

07-28 14:49:25.398: ERROR/AndroidRuntime(8097): 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(2131099717, class android.widget.ListView) with Adapter(class ch.uzh.csg.games4blue.gamebase.view.UserView$UserAdapter)] 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.ListView.layoutChildren(ListView.java:1432) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.AbsListView.onLayout(AbsListView.java:1113) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.view.View.layout(View.java:6831) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:998) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.LinearLayout.onLayout(LinearLayout.java:918) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.view.View.layout(View.java:6831) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1108) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.LinearLayout.onLayout(LinearLayout.java:920) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.view.View.layout(View.java:6831) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.FrameLayout.onLayout(FrameLayout.java:333) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.view.View.layout(View.java:6831) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:998) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.LinearLayout.onLayout(LinearLayout.java:918) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.view.View.layout(View.java:6831) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:998) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.LinearLayout.onLayout(LinearLayout.java:918) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.view.View.layout(View.java:6831) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.FrameLayout.onLayout(FrameLayout.java:333) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.view.View.layout(View.java:6831) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.widget.FrameLayout.onLayout(FrameLayout.java:333) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.view.View.layout(View.java:6831) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.view.ViewRoot.performTraversals(ViewRoot.java:996) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.view.ViewRoot.handleMessage(ViewRoot.java:1633) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.os.Handler.dispatchMessage(Handler.java:99) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.os.Looper.loop(Looper.java:123) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at android.app.ActivityThread.main(ActivityThread.java:4338) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at java.lang.reflect.Method.invokeNative(Native Method) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at java.lang.reflect.Method.invoke(Method.java:521) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) 07-28 14:49:25.398: ERROR/AndroidRuntime(8097): at dalvik.system.NativeStart.main(Native Method) 

Трудно найти ошибку, потому что в stacktrace ни один из моих методов не указан. Итак, кто-нибудь знает, когда это исключение выбрано? Спасибо за любые подсказки.

Вы можете увидеть ошибку в вашем стеке:

Содержимое адаптера изменилось, но ListView не получил уведомление. Убедитесь, что содержимое вашего адаптера не изменено из фонового потока, но только из потока пользовательского интерфейса.

Вы должны изучить один из своих потоков и синхронизировать его с потоком пользовательского интерфейса.

Способ сделать это в Android – это Handler.

http://developer.android.com/guide/appendix/faq/commontasks.html#threading

Он говорит вам, что в классе возникает ошибка: ch.uzh.csg.games4blue.gamebase.view.UserView содержит класс, называемый UserAdapter внутри него.

Позвольте мне объяснить, что здесь происходит. Когда вы создаете ListView с Adapter поддерживающим его, ListView получает свои данные, запрашивая для него адаптер. При каждом прокрутке ListView запрашивает адаптер для новых элементов, которые вы прокручиваете.

Обычно вы создаете ListView, вы создаете адаптер, вы устанавливаете адаптер в списке, и все готово. ОС Android заботится обо всем остальном. Однако, что вы пытаетесь сделать, это немного сложнее. Вы пытаетесь иногда обновлять данные в адаптере. Вы можете себе представить, что список должен быть проинформирован, если данные адаптера изменились, правильно? Если вы показываете список из 2 предметов, и вы вдруг добавляете еще 2 элемента в адаптер, тогда список должен теперь отображать 4 элемента! Однако было бы очень неэффективно, если бы список должен постоянно проверять, изменился ли адаптер, не так ли? Итак, что должно произойти, список будет предполагать, что адаптер не изменяется, и адаптер будет уведомлять о просмотре списка, если он изменится. (Это соглашение между списком и адаптером допускает другие преимущества, такие как listview может кэшировать некоторые из элементов, извлеченных из адаптера для быстрого доступа. Aka, если на экране отображается 10 элементов списка, список может быть уже запрошен 14 элементов. Таким образом, если вы прокручиваете вверх или вниз, по крайней мере, по 2 элемента в любом направлении, у ListView уже есть данные для отображения!)

Однако вы не сделали этого, чтобы уведомить список, что данные внутри адаптера изменились. Где-то внутри UserAdapter или UserView данные изменяются! Чтобы сделать это проще для всех, возможно, вы можете опубликовать полный класс UserView? Моя ставка заключается в том, что у вас есть некоторый объект данных, такой как ArrayList, как приватная переменная внутри класса UserView. Внутри класса UserAdapter вы предоставляете эти данные в ListView. Однако где-то внутри класса UserView вы изменяете этот набор данных, после того как вы уже предоставили его в ListView.

Отказ от ответственности: я в основном копирую другие ответы здесь, но я думаю, что я могу дать более четкое представление о том, что происходит, если я объединю 2-3 ответы

Отказ 2: Я устал, и это кажется плохо написанным. Сделать это вики в надежде, что кто-то очистит мой поздний ночной беспорядок. Если это совершенно непонятно, просто скажите так и больно удалите его

Где вы используете ch.uzh.csg.games4blue.gamebase.view.UserView$UserAdapter .

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

У меня та же проблема, с которой вы столкнулись, я использовал asynchrousTask для заполнения данных в listview. Я решил переписать код, который обновляет Ui в fn

  1. onPostExecute ()
  2. onPreExecute ()

Потому что эта функция работает в потоке пользовательского интерфейса.

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

Я просто исправил это!

Раньше я делал тяжелую обработку, как это, где list был статичным и в классе Activity:

 @Override protected Void doInBackground(Void... arg0) { for (int i=0; i<bigChunk.size(); i++) { list.add(somethingHeavy(i)); } } 

Затем я сделал новый список и добавил его в:

 List<YourObject> listToAdd; @Override protected Void doInBackground(Void... arg0) { listToAdd = new ArrayList<YourObject>(); for (int i=0; i<bigChunk.size(); i++) { listToAdd.add(somethingHeavy(i)); } } @Override protected void onPostExecute(Void result) { list = listToAdd; adapter.notifyDataSetChanged(); }