我通过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)
当我注释掉将可见性更改为可见的行时,我不会得到例外。
我首先想到异常是由一些其他代码迭代通过一个hashmap引起的,但是,我在迭代我使用的哈希映射时没有做任何修改,也没有多线程,这似乎是这种例外的最常见原因。当我不改变能见度时,我也不会得到例外。
修改:
自定义片段中发生异常。下面是我遍历hashmap(mWidgetConfig
)的代码,其中包含有关我尝试恢复的自定义窗口小部件配置的信息。 hashmap是片段中的公共变量。
在片段创建的OnDragListener
中,我根据某个拖动操作更新了hashmap,如下所示:
// Update the widget configuration of the fragment that created this listener
mFragment.mWidgetConfig.put(startCircleTag, "0");
我还迭代了hashmap来检查某个条件,但是在迭代过程中我没有做任何修改:
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;
}
}
此外,在尝试恢复窗口小部件配置时,我在片段中进行了一次迭代。下面是我根据hashmap配置窗口小部件的代码:
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());
}
一旦设置&#34;插头&#34;的可见性的线条以上是在代码中使用的,我得到了例外。
解
抛出异常的原因是我在DragEvent.ACTION_DRAG_ENDED
的{{1}} case语句中调用了配置方法。当我将相同的代码放入OnDragListener
case语句时,异常不会被抛出。不知道为什么。谢谢你的帮助
答案 0 :(得分:16)
据我了解,这是由ViewGroup
实施细节引起的。并且它与多线程无关。
当拖动开始时ViewGroup
创建一个子视图的HashSet,必须通知ACTION_DRAG_ENDED
事件。这是一组可见的孩子。更改子可见性后,相应的ViewGroup
会修改该集(如果其可见性为VISIBLE
则添加子项)。在你的情况下,它会在迭代过程中发生。
请注意,最简单的解决方案是推迟可见性更改。
view.post(new Runnable() {
public void run() {
view.setVisibility(View.VISIBLE);
}
});
将代码放入ACTION_DROP
case语句时不会发生异常,因为在更改视图可见性时不会迭代该集合。
有关详细信息,请参阅ViewGroup.dispatchDragEvent(DragEvent)源代码。
答案 1 :(得分:0)
尝试使用:
setVisibility(View.GONE);
setVisibility(View.VISIBLE);
答案 2 :(得分:0)
另一种可能的解决方案是将可拖动视图包装在某些ViewGroup
中(例如FrameLayout
),并始终保持可见状态。
这样,只有包含在其中的可拖动视图才会消失,留下一个洞(就像之前一样),但是包装器的父级不会收到有关可拖动隐藏的通知。
最后来自
ViewGroup:parent
┗ View:draggable (toggling setVisible on this one, parent gets notified)
到
ViewGroup:parent
┗ ViewGroup:wrapper (setVisible never called on this one)
┗ View:draggable (toggling setVisible on this one, wrapper gets notified)
这里避免使用ConcurrentModificationException
,因为有问题的Map
只包含一个元素,因此完成了一次迭代,这意味着一次调用Iterator.hasNext
/ .next
。
如果这是一个黑客,请自行决定:)
注意:您的修改与问题无关,因为例外情况与ViewGroup.mDragNotifiedChildren
有关,而与Map
无关(请参阅stacktrace),