異なるイベントのリスナーを保持するmEventMapを持ち、addListener()を使用してイベントリスナー、removeListener()およびdispatchEvent()を登録されたリスナーに登録します。 dispatchEvent(中回避方法対話型リスナーの場合はConcurrentModificationException
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();
}
}
…
}
ユースケース
EventListener<Event> mEventListener = new EventListener<Event>(
Event.class) {
@Override
public boolean onEvent(Event event) {
eMgr.removeListener(mEventListener);
// do something
}
};
addEventListener(mEventListener);
)、それはループのremoveListener(にあるとき)と呼ばれ、listenerItem = listenerIteratorでConcurrentModificationExceptionを引き起こします。前();
質問:誰かが反復している間にmEventMapデータの変更によって引き起こされるクラッシュを避ける最良の方法は何ですか?
一つの方法は、すべてのCopyOnWriteArrayListと – m4mbax
まず、リスナーに弱参照を保持しているのアイデアのように...あなたが削除したい要素なしリストをコピーすることであろうことは完璧です足で自分を撃つ方法。これは、聴取者の虚偽の消滅を防ぐために、他の誰かが聴取者に対して強い参照を保持することを必要とする。通常のアプリケーション設計では、そのような必要な参照を保持するものはなく、匿名リスナーインスタンスが標準です。次に、弱い参照のアイデアを放棄したら、(AWTEventMulticasterの背後にある)デザインパターンを見て、イベント配送の堅牢な方法を提供します。リストを複製する必要はありません。 – Holger