我通过setVisibility(View.INVISIBLE)
隐藏了一个视图。稍后,当我尝试通过setVisibility(View.VISIBLE)
以另一种方法再次显示该视图时,遇到以下异常
03-28 01:32:05.450: E/AndroidRuntime(20895): FATAL EXCEPTION: main
03-28 01:32:05.450: E/AndroidRuntime(20895): java.util.ConcurrentModificationException
03-28 01:32:05.450: E/AndroidRuntime(20895): at java.util.HashMap$HashIterator.nextEntry(HashMap.java:796)
03-28 01:32:05.450: E/AndroidRuntime(20895): at java.util.HashMap$KeyIterator.next(HashMap.java:823)
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:946)
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:948)
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:948)
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:948)
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:948)
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:948)
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.view.ViewRoot.handleDragEvent(ViewRoot.java:3027)
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.view.ViewRoot.handleMessage(ViewRoot.java:2185)
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.os.Handler.dispatchMessage(Handler.java:99)
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.os.Looper.loop(Looper.java:132)
03-28 01:32:05.450: E/AndroidRuntime(20895): at android.app.ActivityThread.main(ActivityThread.java:4028)
03-28 01:32:05.450: E/AndroidRuntime(20895): at java.lang.reflect.Method.invokeNative(Native Method)
03-28 01:32:05.450: E/AndroidRuntime(20895): at java.lang.reflect.Method.invoke(Method.java:491)
03-28 01:32:05.450: E/AndroidRuntime(20895): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844)
03-28 01:32:05.450: E/AndroidRuntime(20895): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
03-28 01:32:05.450: E/AndroidRuntime(20895): at dalvik.system.NativeStart.main(Native Method)
当我注解掉将可见性更改回visible的行时,我没有得到异常。
我最初认为这个异常可能是由其他代码迭代哈希Map引起的,然而,我在迭代哈希Map时没有做任何修改,我也没有多线程,这似乎是这个异常最常见的原因。而且,当我不改变可见性时,我也不会得到这个异常。
- 编辑**:
这个异常发生在一个自定义片段中。下面是我迭代hashmap(mWidgetConfig
)的代码,其中包含了我试图恢复的自定义小部件的配置信息。hashmap是片段中的一个公共变量。
在由片段创建的OnDragListener
中,我根据某个拖动操作更新散列表,如下所示:
// Update the widget configuration of the fragment that created this listener
mFragment.mWidgetConfig.put(startCircleTag, "0");
我还迭代哈希Map来检查某个条件,但在迭代过程中不做任何修改:
Iterator<String> keySetItr = mFragment.mWidgetConfig.keySet().iterator();
while(keySetItr.hasNext()) {
String tag = keySetItr.next();
if(mFragment.mWidgetConfig.get(tag).equals((String) destSocket.getTag())) {
// do something, though no modification of the hashmap
break;
}
}
此外,我在尝试恢复小部件配置时对片段本身进行了一次迭代,下面是我用来根据散列表配置小部件的代码:
public void configureWidgets() {
resetWidgets();
Iterator<String> keySetItr = mWidgetConfig.keySet().iterator();
while(keySetItr.hasNext()) {
String tag = keySetItr.next();
Integer value = Integer.parseInt(mWidgetConfig.get(tag));
ImageView destSocket = null;
switch(value) {
case 0:
// The circle will not be connected to any socket
continue;
case 1:
destSocket = mSocket1;
break;
case 2:
destSocket = mSocket2;
break;
case 3:
destSocket = mSocket3;
break;
}
ImageView startCircle = (ImageView) mLayout.findViewWithTag(tag);
ImageView startPlug = (ImageView) mLayout.findViewWithTag(tag + "_plug");
// Replace the drawable of destSocket
destSocket.setBackgroundDrawable(getActivity().getResources().getDrawable(R.drawable.socket_plugged));
// Hide plug view
startPlug.setVisibility(View.INVISIBLE);
// Draw a line between the start circle view and the destination socket view
mConnectionLinesView.addLine(startCircle, destSocket);
}
}
public void resetWidgets() {
// Remove all lines
mConnectionLinesView.removeLines();
// Show all eventually previously hidden plugs
//mPlug1.setVisibility(View.VISIBLE);
//mPlug2.setVisibility(View.VISIBLE);
//mPlug3.setVisibility(View.VISIBLE);
// Set to backround drawable of the socket to the initial one
mSocket1.setBackgroundDrawable(getActivity().getResources().getDrawable(R.drawable.socket).mutate());
mSocket2.setBackgroundDrawable(getActivity().getResources().getDrawable(R.drawable.socket).mutate());
mSocket3.setBackgroundDrawable(getActivity().getResources().getDrawable(R.drawable.socket).mutate());
}
一旦代码中使用了设置上述"plugs"可见性的行,我就得到了异常。
- 解决方案**
抛出异常的原因是我调用了OnDragListener
的DragEvent.ACTION_DRAG_ENDED
case语句中的配置方法。当我把相同的代码放入DragEvent.ACTION_DROP
case语句中时,没有抛出异常。不知道为什么。谢谢你们的帮助
3条答案
按热度按时间oewdyzsn1#
据我所知,这是由
ViewGroup
实现细节引起的,与多线程无关。当拖动开始时,
ViewGroup
创建一个必须被通知ACTION_DRAG_ENDED
事件的子视图的HashSet。这是一个可见子视图的集合。当子视图可见性改变时,相应的ViewGroup
修改该集合(如果其可见性为VISIBLE
,则添加一个子视图)。在您的情况下,它发生在该集合的迭代过程中。想想看,对你来说最简单的解决方案就是推迟可见性的改变。
当您将代码放入
ACTION_DROP
case语句时,不会发生异常,因为在更改视图可见性时,该集合不会被迭代。有关详细信息,请参见ViewGroup.dispatchDragEvent(DragEvent)源代码。
u4dcyp6a2#
尝试使用:
lymnna713#
另一种可能的解决方案是将可拖动视图 Package 在某个
ViewGroup
中(例如FrameLayout
),并始终保持其可见。这样,只有包含在其中的可拖动视图会消失,在原来的位置留下一个洞(就像以前一样),但是 Package 器的父级不会得到可拖动视图被隐藏的通知。
基本上从
到
这里避免了
ConcurrentModificationException
,因为有问题的Map
只包含一个元素,因此进行了一次迭代,这意味着对Iterator.hasNext
/.next
的一次调用。注意:您的编辑与问题无关,因为例外是关于
ViewGroup.mDragNotifiedChildren
的,而不是您的Map
(参见stacktrace),