-1

I have found a same question in I used synchronized list, and i still get ConcurrentModificationException, but i didn't find a correct answer.

Here is how i defined my synchronized list:

private List<ActionItemClickListener> actionItemClickListeners = Collections.synchronizedList(new ArrayList<ActionItemClickListener>());

And here is how i used it:

@Override
public void onBackPressed() {
    boolean isConsume = false;
    synchronized (actionItemClickListeners) {
        //ConcurrentModificationException occur here
        for (ActionItemClickListener listener : actionItemClickListeners) {
            isConsume = isConsume | listener.onSystemBackPressed();
        }
    }
    if(!isConsume) {
        pendingFragment = null;
        pendingTag = null;
        currentFragmentTag = null;
        super.onBackPressed();
    }
}
public void addActionItemClickListener(ActionItemClickListener listener) {
        synchronized (actionItemClickListeners) {
            if (listener != null)
                actionItemClickListeners.add(listener);
        }
}

public void removeActionItemClickListener(ActionItemClickListener listener) {
        synchronized (actionItemClickListeners) {
            if (listener != null)
                actionItemClickListeners.remove(listener);
        }
}

Why i'm still getting ConcurrentModificationException???

Community
  • 1
  • 1
mr.icetea
  • 2,607
  • 3
  • 24
  • 42

1 Answers1

2

Your ConcurrentModificationException is not a thread issue. It is thrown because you are modifying a list while iterating through it.

for (ActionItemClickListener listener : actionItemClickListeners) {
    isConsume = isConsume | listener.onSystemBackPressed();
}

The problem is that listener.onSystemBackPressed(); is calling removeActionItemClickListener, which attempts to change the actionItemClickListeners which you are in the process of iterating through. Trying to change a list that you are iterating through will cause a ConcurrentModificationException

How to fix

Without seeing the rest of your code, I can only guess as to how to fix this, but you could use iterator.next(), iterator.hasNext() and iterator.remove() for looping through and removing the the listener, respectively. You would either need to pass the iterator through onSystemBackPressed() and removeActionItemClickListener, which is a little ugly, or have onSystemBackPressed() return a boolean value indicating if it should remove the listener.

final Iterator<String> iterator = actionItemClickListeners.iterator();
while (iterator.hasNext()) {
    final String listener = iterator.next();
    final boolean removeListener = listener.onSystemBackPressed();
    if (removeListener) {
        iterator.remove();
    }
    isConsume = isConsume | removeListener;
}

Unfortunately, it looks like you are using the return value of onSystemBackPressed() for something else, so that may not work either.

pathfinderelite
  • 3,047
  • 1
  • 27
  • 30
  • Thank for your explanation. Can you help me find a solution for my case? – mr.icetea May 16 '15 at 12:43
  • @mr.icetea Added possible solution to answer. However, it's hard to say if it will be helpful without having more detail. In any case, you can use `Iterator` like above to remove from the list while iterating through it, so that will hopefully help lead you to a solution. – pathfinderelite May 16 '15 at 13:03