【问题标题】:How to diagnose Android ConcurrentModificationException如何诊断Android ConcurrentModificationException
【发布时间】:2012-12-14 21:25:38
【问题描述】:

我有一个通过 Eclipse 调试的 Android Google Maps 应用程序。我收到此错误:

    12-14 16:19:50.106: E/AndroidRuntime(2487): FATAL EXCEPTION: main
12-14 16:19:50.106: E/AndroidRuntime(2487): java.util.ConcurrentModificationException
12-14 16:19:50.106: E/AndroidRuntime(2487):     at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at com.google.android.maps.OverlayBundle.draw(OverlayBundle.java:41)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at com.google.android.maps.MapView.onDraw(MapView.java:494)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.view.View.draw(View.java:6740)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.view.ViewGroup.drawChild(ViewGroup.java:1640)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.view.View.draw(View.java:6743)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.widget.FrameLayout.draw(FrameLayout.java:352)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.view.ViewGroup.drawChild(ViewGroup.java:1640)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.view.View.draw(View.java:6743)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.widget.FrameLayout.draw(FrameLayout.java:352)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1842)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.view.ViewRoot.draw(ViewRoot.java:1407)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.view.ViewRoot.performTraversals(ViewRoot.java:1163)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1727)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.os.Handler.dispatchMessage(Handler.java:99)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.os.Looper.loop(Looper.java:123)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at android.app.ActivityThread.main(ActivityThread.java:4627)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at java.lang.reflect.Method.invokeNative(Native Method)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at java.lang.reflect.Method.invoke(Method.java:521)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
12-14 16:19:50.106: E/AndroidRuntime(2487):     at dalvik.system.NativeStart.main(Native Method)

我从不显式使用迭代器(我的代码没有,尽管显然某些调用包含一个),并且我确保任何类型的列表只能通过从 Collections.synchronizedList 返回的内容访问,这应该已经解决这个,以我有限的理解。因为我不知道我的代码库中的什么会导致这种情况,所以我不能真正发布代码 sn-ps。有谁知道其他“正常”原因?或者如何从 logcat 打印输出中获取任何有意义的位置(据我所知,唯一的文件引用是库文件)?

【问题讨论】:

  • "我从不明确使用迭代器" -- 你会注意到 onDraw()MapView 有迭代器。 “因为我似乎无法从 LogCat 复制和粘贴”——在 Eclipse 中,突出显示 LogCat 中的行并按 Ctrl-C。
  • Collections.synchronizedList 实际上并没有解决这个问题。如果在使用迭代器(包括增强的 for 循环)时更改列表,则会发生异常。同步单个方法调用不会停止在迭代器调用之间更改列表。
  • 我看到它是 MapView 的 onDraw,但这不是我写的代码,所以我假设它是自动生成的或库代码?我可能会做什么会导致我没有编写的代码出现问题?
  • (对不起,这太模糊了,但我认为将大量代码块复制粘贴到问题中对我来说是一种不好的形式,我不知道如何调试它)

标签: java android concurrency runtime-error


【解决方案1】:

我假设它是自动生成的或库代码?

这是库代码。

我可能会做什么,这会导致我没有编写的代码出现问题?

您正在修改后台线程中的集合,该集合正在主应用程序线程中进行迭代,例如通过在后台线程中添加或删除覆盖。

不幸的是,Android 版 Google Maps API 的经典版和 V2 版都不是开源的,因此很难从堆栈跟踪中准确判断发生了什么。我的猜测是您正在后台线程中添加或删除叠加层。

【讨论】:

  • 哦,有道理。是的,我在回调函数中添加/删除覆盖。我在叠加层中有很多点,所以当视图窗口发生变化时,我会删除旧叠加层,并将新点生成到新叠加层。手动单步遍历叠加层并删除每个点以便我可以重复使用叠加层的正确方法是否正确?
  • @Akroy:“手动单步遍历覆盖并删除每个点以便我可以重复使用覆盖的正确方法是否正确?” -- 如果这是一个ItemizedOverlay,正确的方法是在您准备好替换您在上次populate() 调用中提供的内容时,在ItemizedOverlay 上调用populate()。您将需要在主应用程序线程 AFAIK 上调用 populate()
  • 原谅一个新手;我正在阅读有关填充的信息,但我仍然不清楚。 populate 是否基本上转储了之前 ItemizedOverlay 中的所有内容,留下一个空的 Overlay 以重复使用?
  • @Akroy:“populate 是否基本上转储了之前 ItemizedOverlay 中的所有内容,留下一个空的 Overlay 以供重复使用?” -- populate() 转储旧项目并再次调用size()getItem() 等以重新加载OverlayItem 名册,与第一次调用populate() 时相同。
  • 我认为这有点道理;我可能可以从这里找到解决方案。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-25
  • 2010-11-27
  • 1970-01-01
相关资源
最近更新 更多