Mit einer mEventMap, um die Listener für verschiedene Ereignisse zu halten, und hat addListener(), um die Ereignislistener, removeListener() und dispatchEvent() zu den registrierten Listenern zu registrieren.So vermeiden ConcurrentModificationException für den Listener-Fall
public void addListener(EventListener listener) {
synchronized (mEventMap) {
List<WeakReference<EventListener<Event>>> listeners = mEventMap.get(listener.mEventClass);
WeakReference<EventListener<Event>> listenerRef = new WeakReference<>(
(EventListener<Event>) listener)
…
listeners.add(listenerRef);
…
}
}
public void removeListener(EventListener listener) {
synchronized (mEventMap) {
List<WeakReference<EventListener<Event>>> listeners = mEventMap.get(listener.mEventClass);
…
if (contains(listeners, listener)) {
doRemove(listeners, listener);
}
…
}
}
public boolean dispatchEvent(Event event) {
synchronized (mEventMap) {
List<WeakReference<EventListener<Event>>> listeners = mEventMap.get(event.getClass());
ListIterator<WeakReference<EventListener<Event>>> listenerIterator = listeners.listIterator(listeners.size());
…
while (listenerIterator.hasPrevious()) {
WeakReference<EventListener<Event>> listenerItem = listenerIterator.previous();
EventListener<Event> listenerRef = listenerItem.get();
if (listenerRef != null) {
listenerRef.onEvent(event);
} else {
listenerIterator.remove();
}
}
…
}
Anwendungsfall
EventListener<Event> mEventListener = new EventListener<Event>(
Event.class) {
@Override
public boolean onEvent(Event event) {
eMgr.removeListener(mEventListener);
// do something
}
};
addEventListener(mEventListener);
in dispatch(), während es in der Schleife ist das removeListener() aufgerufen wird und bewirkt, dass die ConcurrentModificationException bei listenerItem = listenerIterator. Bisherige();
Frage: Was ist der beste Weg, um den Absturz zu vermeiden, der durch die Änderung der mEventMap-Daten verursacht wird, während jemand darauf iteriert.
Eine Möglichkeit, die Liste ohne das Element, das Sie entfernen möchten, kopieren wäre ... Wie CopyOnWriteArrayList – m4mbax
Vor allem der Idee des Haltens schwachen Verweises auf Zuhörer ist die perfekte Möglichkeit, sich in den Fuß zu schießen. Das erfordert, dass jemand anders einen starken Bezug zum Zuhörer hält, um das unechte Verschwinden von Zuhörern zu verhindern. Im üblichen Anwendungsdesign gibt es niemanden, der solche erforderlichen Referenzen hält und anonyme Listener-Instanzen sind die Norm. Wenn Sie dann die Idee der schwachen Referenzen aufgegeben haben, sehen Sie sich das Entwurfsmuster hinter "AWTEventMulticaster" an, das eine robuste Art der Ereignisauslieferung bietet und immun gegen Hinzufügungen und Entfernungen zwischen den beiden ist (ohne dass eine Liste geklont werden muss). – Holger