Commit 13e0513e by olly Committed by Oliver Woodman

Give EventDispatcher more predictable behavior

If EventDispatcher.removeListener is called to remove a listener,
and if the call is made from the same thread that said listener
handles events on, then it should be guaranteed that the listener
will not be subsequently invoked on that thread.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=218331427
parent 5ae60a6f
......@@ -39,22 +39,23 @@ public final class EventDispatcher<T> {
/** The list of listeners and handlers. */
private final CopyOnWriteArrayList<HandlerAndListener<T>> listeners;
/** Creates event dispatcher. */
/** Creates an event dispatcher. */
public EventDispatcher() {
listeners = new CopyOnWriteArrayList<>();
}
/** Adds listener to event dispatcher. */
/** Adds a listener to the event dispatcher. */
public void addListener(Handler handler, T eventListener) {
Assertions.checkArgument(handler != null && eventListener != null);
removeListener(eventListener);
listeners.add(new HandlerAndListener<>(handler, eventListener));
}
/** Removes listener from event dispatcher. */
/** Removes a listener from the event dispatcher. */
public void removeListener(T eventListener) {
for (HandlerAndListener<T> handlerAndListener : listeners) {
if (handlerAndListener.listener == eventListener) {
handlerAndListener.release();
listeners.remove(handlerAndListener);
}
}
......@@ -67,19 +68,33 @@ public final class EventDispatcher<T> {
*/
public void dispatch(Event<T> event) {
for (HandlerAndListener<T> handlerAndListener : listeners) {
T eventListener = handlerAndListener.listener;
handlerAndListener.handler.post(() -> event.sendTo(eventListener));
handlerAndListener.dispatch(event);
}
}
private static final class HandlerAndListener<T> {
public final Handler handler;
public final T listener;
private final Handler handler;
private final T listener;
private boolean released;
public HandlerAndListener(Handler handler, T eventListener) {
this.handler = handler;
this.listener = eventListener;
}
public void release() {
released = true;
}
public void dispatch(Event<T> event) {
handler.post(
() -> {
if (!released) {
event.sendTo(listener);
}
});
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment