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. */
|
||||
public void clear() {
|
||||
verifyCurrentThread();
|
||||
for (ListenerHolder<T> listenerHolder : listeners) {
|
||||
listenerHolder.release(iterationFinishedEvent);
|
||||
}
|
||||
listeners.clear();
|
||||
}
|
||||
|
||||
|
@ -333,6 +333,55 @@ public class ListenerSetTest {
|
||||
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
|
||||
public void release_stopsForwardingEventsImmediately() {
|
||||
ListenerSet<TestListener> listenerSet =
|
||||
|
Loading…
x
Reference in New Issue
Block a user