Android: IllegalStateException - Когда это брошено? - PullRequest
7 голосов
/ 28 июля 2010

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

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)

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

Ответы [ 6 ]

22 голосов
/ 29 июля 2010

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

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

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

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

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

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

4 голосов
/ 28 июля 2010

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

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

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

В Android это можно сделать с помощью обработчика.

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

2 голосов
/ 28 июля 2010

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

1 голос
/ 12 августа 2011

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

  1. onPostExecute ()
  2. onPreExecute ()

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

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

1 голос
/ 28 июля 2010

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

0 голосов
/ 10 февраля 2012

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

Ранее я выполнял тяжелую обработку, подобную этой, где 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();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...