Android - setVisibility导致java.util.ConcurrentModificationException

Sch*_*pfe 8 android android-layout

我正在隐藏一个视图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)
Run Code Online (Sandbox Code Playgroud)

当我注释掉将可见性更改为可见的行时,我没有得到异常.

我首先想到异常是由一些其他代码迭代遍历hashmap引起的,但是,我在迭代我使用的哈希图时没有做任何修改,也没有多线程,这似乎是最常见的原因.这个例外.当我不改变能见度时,我也没有得到例外.

编辑:
自定义片段中发生异常.下面是我遍历hashmap(mWidgetConfig)的代码,其中包含有关我尝试恢复的自定义窗口小部件配置的信息.hashmap是片段中的公共变量.

OnDragListener片段创建的片段中,我根据某个拖动操作更新了hashmap,如下所示:

// Update the widget configuration of the fragment that created this listener
                mFragment.mWidgetConfig.put(startCircleTag, "0");
Run Code Online (Sandbox Code Playgroud)

我还迭代了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;

            }
        }
Run Code Online (Sandbox Code Playgroud)

另外,在尝试恢复小部件配置时,我在片段本身中进行了一次迭代.下面是我根据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());
}
Run Code Online (Sandbox Code Playgroud)

只要在代码中使用了设置上面"插件"可见性的行,我就会得到异常.

解决方案
抛出异常的原因是我调用了DragEvent.ACTION_DRAG_ENDEDcase语句中的配置方法OnDragListener.当我将相同的代码放入DragEvent.ACTION_DROPcase语句时,异常不会被抛出.不知道为什么.谢谢你的帮助

Rom*_*zur 16

据我所知,这是由ViewGroup实现细节引起的.它与多线程无关.

拖动开始时ViewGroup会创建一个必须通知ACTION_DRAG_ENDED事件的子视图的HashSet .这是一组可见的孩子.当子可见性发生变化时,相应的ViewGroup会修改该集合(如果其可见性是添加子项VISIBLE).在您的情况下,它会在迭代过程中发生.

想想,最简单的解决方案是推迟可见性变化.

view.post(new Runnable() {
  public void run() {
    view.setVisibility(View.VISIBLE);
  }
});
Run Code Online (Sandbox Code Playgroud)

将代码放入ACTION_DROPcase语句时不会发生异常,因为在更改视图可见性时不会迭代该集合.

有关详细信息,请参阅ViewGroup.dispatchDragEvent(DragEvent)源代码.


小智 0

尝试使用:

setVisibility(View.GONE);
setVisibility(View.VISIBLE);
Run Code Online (Sandbox Code Playgroud)