Release all ListenerHolders when clearing ListenerSet
When removing one listener from the `ListenerSet`, we release the corresponding `ListenerHolder`, which prevents the event queued or sent later than the removal from being invoked. We should also do this in the method `ListenerSet.clear()` where every listener is removed. PiperOrigin-RevId: 652535216
This commit is contained in:
parent
d747f38f59
commit
ec1954c1d5
@ -198,6 +198,9 @@ public final class ListenerSet<T extends @NonNull Object> {
|
|||||||
/** Removes all listeners from the set. */
|
/** Removes all listeners from the set. */
|
||||||
public void clear() {
|
public void clear() {
|
||||||
verifyCurrentThread();
|
verifyCurrentThread();
|
||||||
|
for (ListenerHolder<T> listenerHolder : listeners) {
|
||||||
|
listenerHolder.release(iterationFinishedEvent);
|
||||||
|
}
|
||||||
listeners.clear();
|
listeners.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,6 +333,55 @@ public class ListenerSetTest {
|
|||||||
verifyNoMoreInteractions(listener1, listener2);
|
verifyNoMoreInteractions(listener1, listener2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clear_withRecursion_stopsReceivingEventsImmediately() {
|
||||||
|
ListenerSet<TestListener> listenerSet =
|
||||||
|
new ListenerSet<>(Looper.myLooper(), Clock.DEFAULT, TestListener::iterationFinished);
|
||||||
|
TestListener listener2 = mock(TestListener.class);
|
||||||
|
// Listener1 clears the set from within the callback.
|
||||||
|
TestListener listener1 =
|
||||||
|
spy(
|
||||||
|
new TestListener() {
|
||||||
|
@Override
|
||||||
|
public void callback1() {
|
||||||
|
listenerSet.clear();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
listenerSet.add(listener1);
|
||||||
|
listenerSet.add(listener2);
|
||||||
|
|
||||||
|
// Listener2 shouldn't even get this event as the set was cleared before the event can be
|
||||||
|
// invoked.
|
||||||
|
listenerSet.sendEvent(EVENT_ID_1, TestListener::callback1);
|
||||||
|
listenerSet.sendEvent(EVENT_ID_2, TestListener::callback2);
|
||||||
|
ShadowLooper.idleMainLooper();
|
||||||
|
|
||||||
|
verify(listener1).callback1();
|
||||||
|
// Listener1 should receive IterationFinishedEvent as the first event was invoked before the
|
||||||
|
// set was cleared.
|
||||||
|
verify(listener1).iterationFinished(createFlagSet(EVENT_ID_1));
|
||||||
|
verifyNoMoreInteractions(listener1, listener2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clear_withQueueing_stopsReceivingEventsImmediately() {
|
||||||
|
ListenerSet<TestListener> listenerSet =
|
||||||
|
new ListenerSet<>(Looper.myLooper(), Clock.DEFAULT, TestListener::iterationFinished);
|
||||||
|
TestListener listener1 = mock(TestListener.class);
|
||||||
|
TestListener listener2 = mock(TestListener.class);
|
||||||
|
listenerSet.add(listener1);
|
||||||
|
listenerSet.add(listener2);
|
||||||
|
|
||||||
|
// Both Listener1 and Listener2 shouldn't even get this event as they are cleared before the
|
||||||
|
// event can be invoked.
|
||||||
|
listenerSet.queueEvent(EVENT_ID_1, TestListener::callback1);
|
||||||
|
listenerSet.clear();
|
||||||
|
listenerSet.flushEvents();
|
||||||
|
ShadowLooper.idleMainLooper();
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(listener1, listener2);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void release_stopsForwardingEventsImmediately() {
|
public void release_stopsForwardingEventsImmediately() {
|
||||||
ListenerSet<TestListener> listenerSet =
|
ListenerSet<TestListener> listenerSet =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user