I'm implementing drag'n'drop for views. When drag is started, I set visibility of the view to INVISIBLE
, then, if the drag was interrupted - back to 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) } } }
And:
if (event.getAction() == DragEvent.ACTION_DRAG_ENDED) { View droppedView = (View) event.getLocalState(); droppedView.setVisibility(View.VISIBLE); }
And when "Drag ended" event is called, I'm getting exception:
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)
Why and how to fix it?
How do you fix Java's ConcurrentModificationException? There are two basic approaches: Do not make any changes to a collection while an Iterator loops through it. If you can't stop the underlying collection from being modified during iteration, create a clone of the target data structure and iterate through the clone.
What Causes ConcurrentModificationException. The ConcurrentModificationException generally occurs when working with Java Collections. The Collection classes in Java are very fail-fast and if they are attempted to be modified while a thread is iterating over it, a ConcurrentModificationException is thrown.
The ConcurrentModificationException occurs when an object is tried to be modified concurrently when it is not permissible. This exception usually comes when one is working with Java Collection classes. For Example - It is not permissible for a thread to modify a Collection when some other thread is iterating over it.
Iterator implementations that throw ConcurrentModificationException are known as fail-fast iterators, as they fail quickly and cleanly, rather than risking arbitrary, non-deterministic behavior later.
You can try this
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); } }); }
Looks like Android itself trying to access View state at the same time as you end dragging.
EDIT
More precise explanation. By setting setVisibility()
, you're including or excluding View
from Android internal collection of views, that should respond to drag events. This collection is used during dispatch of drag events, and therefore by trying to setVisibility
(in other words, trying to modify listeners of drag events) you're causing ConcurrentModificationException
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With