在我的应用程序中,有时会抛出以下异常:
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)
很难找到错误,因为在堆栈跟踪中没有列出任何方法。那么,有没有人知道什么时候抛出这个异常?感谢任何提示。
答案 0 :(得分:22)
它确实告诉你发生错误的类:ch.uzh.csg.games4blue.gamebase.view.UserView
里面包含一个名为UserAdapter
的类。
让我试着解释一下这里发生了什么 - 当你创建ListView
并Adapter
进行备份时,ListView
会通过向适配器询问数据来获取数据。每次滚动时,ListView都会向适配器询问您滚动到的新项目。
通常你创建ListView,你创建适配器,你在listview上设置适配器,你就完成了。 Android OS负责其余部分。但是,您尝试做的事情有点复杂。您试图偶尔更新适配器中的数据。您可以想象,如果适配器数据发生变化,则需要通知列表视图,对吧?如果您正在显示包含2个项目的列表,并且您突然向适配器添加了2个项目,那么该列表现在应该显示4个项目!但是,如果listview必须不断检查适配器是否已更改,那么效率会非常低,对吧?所以需要发生的是listview将假定适配器不会更改,并且适配器将通知listview它是否确实更改。 (listview和适配器之间的这个协议允许其他好处,例如listview可以缓存从适配器检索的一些项目以便快速访问。如果屏幕上显示10个列表项,Aka可能实际上已经请求了14项。这样,如果向上或向下滚动,在任一方向上至少有2个项目,ListView已经有数据要显示!)
但是,您未能做的是通知列表视图适配器内的数据发生了变化。在UserAdapter或UserView内的某处,数据正在被更改!为了方便每个人,也许您可以发布完整的UserView类?我敢打赌,你有一些数据对象,如ArrayList,作为UserView类中的私有变量。在UserAdapter类中,您将此数据提供给ListView。但是,在UserView类的某个内部,您正在修改此数据集,在之后已将其提供给ListView。
免责声明:我主要是在这里复制其他答案,但我认为如果我将2-3个答案结合起来,我可以更清楚地了解正在发生的事情
免责声明2:我很累,这写得很糟糕。把它变成一个维基,希望有人清理我深夜的烂摊子。如果这是完全无法理解的,那就这么说并且删除它
答案 1 :(得分:4)
您可以在堆栈跟踪中看到错误:
适配器的内容已更改 但是ListView没有收到 通知。确保内容 您的适配器未从a修改 后台线程,但只来自 UI线程。
您应该查看一个线程并使其与UI线程同步。
在Android中执行此操作的方法是使用Handler。
http://developer.android.com/guide/appendix/faq/commontasks.html#threading
答案 2 :(得分:2)
您使用ch.uzh.csg.games4blue.gamebase.view.UserView$UserAdapter
的位置。
答案 3 :(得分:1)
实际上,当您修改适配器的内容时会发送此类错误,而不会使用适配器通知您的列表视图或任何其他视图,其内容应该更新。
尝试在适配器上调用.notifyDataSetChanged()
。
答案 4 :(得分:1)
我遇到了同样的问题我正在使用asynchrousTask填充listview中的数据。我通过重写代码来解决fn中更新Ui的问题
因为这些函数在UI线程中运行。
希望这有帮助。
答案 5 :(得分:0)
我刚刚解决了这个问题!
之前我正在进行这样的繁重处理,其中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();
}