0

I have a HashMap that gets created in my method

final HashMap<Long, Rect> listViewItemBounds = new HashMap<Long, Rect>();

that saves all the bounds of visible views in a ListView

for (int i = 0; i < getChildCount(); ++i) {
    View child = getChildAt(i);
    if(child != null){
        int position = firstVisiblePosition+i;
        long itemID = adapter.getItemId(position);
        Rect startRect = new Rect(child.getLeft(), child.getTop(), child.getRight(),child.getBottom());
        listViewItemBounds.put(itemID, startRect);
        listViewItemDrawables.put(itemID, getBitmapDrawableFromView(child));
    }

}

then I start an OnPreDrawListener on the ListView

final ViewTreeObserver observer = getViewTreeObserver();
    observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
    public boolean onPreDraw() {
        .
        .  
        .
    }
)};

and in the onPreDrawListener I loop through he hashmap to get the bounds of the saved views

for (Long itemId: listViewItemBounds.keySet()) { //points here
    .
    .
    .
    istViewItemBounds.remove(itemId);
}

the problem comes when I change/update the adapter where all this gets called again and onPreDraw is currently looping through the hashmap while it is being updated again due to the adapter change.

So how can I prevent the concurrency here so I dont get ConcurrentModificationException?

Stacktrace:

08-31 19:09:41.398  29127-29127/? E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.util.ConcurrentModificationException
            at java.util.HashMap$HashIterator.nextEntry(HashMap.java:792)
            at java.util.HashMap$KeyIterator.next(HashMap.java:819)
            at com.tyczj.myapp.views.HeaderGridView$3.onPreDraw(HeaderGridView.java:511)
            at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:680)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1842)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:989)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4351)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
            at android.view.Choreographer.doCallbacks(Choreographer.java:562)
            at android.view.Choreographer.doFrame(Choreographer.java:532)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
            at android.os.Handler.handleCallback(Handler.java:725)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5041)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
            at dalvik.system.NativeStart.main(Native Method)

Edit:

Iterator<Long> it = listViewItemBounds.keySet().iterator();
    while(it.hasNext()){
        long itemId = it.next(); //error
    }
Teng-pao Yu
  • 1,313
  • 15
  • 30
tyczj
  • 71,600
  • 54
  • 194
  • 296

1 Answers1

2

You can never remove entries from a hashMap while iterating over its keySet unless you do it using an Iterator and use its remove() method. This is where the ConcurrentModificationException comes from. It's nothing to do with threads.

Paul Boddington
  • 37,127
  • 10
  • 65
  • 116