Java.util.ConcurrentModificationException в View.setVisibility

Я использую drag'n'drop для просмотров. Когда началось перетаскивание, я установил видимость представления в INVISIBLE, затем, если перетащить было прервано - вернитесь к VISIBLE:

public boolean onTouch(View v, MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        // Skipped some code
        boolean dragStarted = v.startDrag(data, shadowBuilder, v, 0);

        if (dragStarted) {
            v.setVisibility(View.INVISIBLE)
        }
    }
}

и

if (event.getAction() == DragEvent.ACTION_DRAG_ENDED) {
    View droppedView = (View) event.getLocalState();
    droppedView.setVisibility(View.VISIBLE);
}

И когда вызывается событие "Перетаскивание", я получаю исключение:

E/AndroidRuntime(7118): FATAL EXCEPTION: main 
E/AndroidRuntime(7118): java.util.ConcurrentModificationException 
E/AndroidRuntime(7118):     at java.util.HashMap$HashIterator.nextEntry(HashMap.java:792)
E/AndroidRuntime(7118):     at java.util.HashMap$KeyIterator.next(HashMap.java:819) 
E/AndroidRuntime(7118):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1046)
E/AndroidRuntime(7118):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1048)
E/AndroidRuntime(7118):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1048)
E/AndroidRuntime(7118):     at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1048)
E/AndroidRuntime(7118):     at android.view.ViewRootImpl.handleDragEvent(ViewRootImpl.java:3471)
E/AndroidRuntime(7118):     at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2620)
E/AndroidRuntime(7118):     at android.os.Handler.dispatchMessage(Handler.java:99) 
E/AndroidRuntime(7118):     at android.os.Looper.loop(Looper.java:137) 
E/AndroidRuntime(7118):     at android.app.ActivityThread.main(ActivityThread.java:4575)
E/AndroidRuntime(7118):     at java.lang.reflect.Method.invokeNative(Native Method) 
E/AndroidRuntime(7118):     at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime(7118):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
E/AndroidRuntime(7118):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:556)
E/AndroidRuntime(7118):     at dalvik.system.NativeStart.main(NativeMethod)

Почему и как его исправить?

Ответы

Ответ 1

Вы можете попробовать это

if (event.getAction() == DragEvent.ACTION_DRAG_ENDED) {
    final View droppedView = (View) event.getLocalState();
    droppedView.post(new Runnable(){
        @Override
        public void run() {
            droppedView.setVisibility(View.VISIBLE);
        }
    });
}

Похоже, что сам Android пытается получить доступ к представлению в то же время, что и вы перетаскиваете.

ИЗМЕНИТЬ

Более точное объяснение. Установив setVisibility(), вы включаете или исключаете View из внутренней коллекции просмотров Android, которая должна реагировать на события перетаскивания. Эта коллекция используется при отправке событий перетаскивания и, следовательно, при попытке setVisibility (другими словами, при попытке изменить прослушиватели событий перетаскивания) вы вызываете ConcurrentModificationException

Ответ 2

Лучший способ это:

    view.post(new Runnable() {
  public void run() {
    view.setVisibility(View.VISIBLE);
  }
});

если мы используем:

 if (event.getAction() == DragEvent.ACTION_DRAG_ENDED) {
    final View droppedView = (View) event.getLocalState();
    droppedView.post(new Runnable(){
        @Override
        public void run() {
            droppedView.setVisibility(View.VISIBLE);
        }
    });
}

вы все равно получите силу при закрытии Null.pointer....

Ответ 3

Возможно, этот может помочь. здесь в данной ссылке говорится: вместо DragEvent.ACTION_DRAG_ENDED используйте DragEvent.ACTION_DROP.