Skip to content

Commit 6f94099

Browse files
toniheicopybara-github
authored andcommitted
Make it easier to use ListenerSet without completion listener
In some cases the iteration completion listener is not required. For such ListenerSets, the constructor can be shorter, and the event reporting doesn't need to specify flags. PiperOrigin-RevId: 819746087
1 parent 37dc968 commit 6f94099

File tree

7 files changed

+105
-44
lines changed

7 files changed

+105
-44
lines changed

libraries/common/src/main/java/androidx/media3/common/util/ListenerSet.java

Lines changed: 92 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public interface IterationFinishedEvent<T> {
7979

8080
private final Clock clock;
8181
private final HandlerWrapper handler;
82-
private final IterationFinishedEvent<T> iterationFinishedEvent;
82+
@Nullable private final IterationFinishedEvent<T> iterationFinishedEvent;
8383
private final CopyOnWriteArraySet<ListenerHolder<T>> listeners;
8484
private final ArrayDeque<Runnable> flushingEvents;
8585
private final ArrayDeque<Runnable> queuedEvents;
@@ -90,16 +90,37 @@ public interface IterationFinishedEvent<T> {
9090

9191
private boolean throwsWhenUsingWrongThread;
9292

93+
/**
94+
* Creates a new listener set.
95+
*
96+
* <p>This listener set will not send an {@link IterationFinishedEvent} when all other events sent
97+
* during one {@link Looper} message queue iteration were handled by the listeners.
98+
*
99+
* @param looper A {@link Looper} used to call listeners on. The same {@link Looper} must be used
100+
* to call all other methods of this class unless indicated otherwise.
101+
* @param clock A {@link Clock}.
102+
*/
103+
public ListenerSet(Looper looper, Clock clock) {
104+
this(
105+
/* listeners= */ new CopyOnWriteArraySet<>(),
106+
looper,
107+
clock,
108+
/* iterationFinishedEvent= */ null,
109+
/* throwsWhenUsingWrongThread= */ true);
110+
}
111+
93112
/**
94113
* Creates a new listener set.
95114
*
96115
* @param looper A {@link Looper} used to call listeners on. The same {@link Looper} must be used
97116
* to call all other methods of this class unless indicated otherwise.
98117
* @param clock A {@link Clock}.
99118
* @param iterationFinishedEvent An {@link IterationFinishedEvent} sent when all other events sent
100-
* during one {@link Looper} message queue iteration were handled by the listeners.
119+
* during one {@link Looper} message queue iteration were handled by the listeners, or null if
120+
* no such event is needed.
101121
*/
102-
public ListenerSet(Looper looper, Clock clock, IterationFinishedEvent<T> iterationFinishedEvent) {
122+
public ListenerSet(
123+
Looper looper, Clock clock, @Nullable IterationFinishedEvent<T> iterationFinishedEvent) {
103124
this(
104125
/* listeners= */ new CopyOnWriteArraySet<>(),
105126
looper,
@@ -112,7 +133,7 @@ private ListenerSet(
112133
CopyOnWriteArraySet<ListenerHolder<T>> listeners,
113134
Looper looper,
114135
Clock clock,
115-
IterationFinishedEvent<T> iterationFinishedEvent,
136+
@Nullable IterationFinishedEvent<T> iterationFinishedEvent,
116137
boolean throwsWhenUsingWrongThread) {
117138
this.clock = clock;
118139
this.listeners = listeners;
@@ -134,14 +155,42 @@ private ListenerSet(
134155
*
135156
* @param looper The new {@link Looper} for the copied listener set.
136157
* @param iterationFinishedEvent The new {@link IterationFinishedEvent} sent when all other events
137-
* sent during one {@link Looper} message queue iteration were handled by the listeners.
158+
* sent during one {@link Looper} message queue iteration were handled by the listeners, or
159+
* null if no such event is needed.
160+
* @return The copied listener set.
161+
*/
162+
@CheckResult
163+
public ListenerSet<T> copy(
164+
Looper looper, @Nullable IterationFinishedEvent<T> iterationFinishedEvent) {
165+
return copy(looper, clock, iterationFinishedEvent);
166+
}
167+
168+
/**
169+
* Copies the listener set.
170+
*
171+
* <p>This method can be called from any thread.
172+
*
173+
* @param looper The new {@link Looper} for the copied listener set.
138174
* @return The copied listener set.
139175
*/
140176
@CheckResult
141-
public ListenerSet<T> copy(Looper looper, IterationFinishedEvent<T> iterationFinishedEvent) {
177+
public ListenerSet<T> copy(Looper looper) {
142178
return copy(looper, clock, iterationFinishedEvent);
143179
}
144180

181+
/**
182+
* Copies the listener set.
183+
*
184+
* <p>This method can be called from any thread.
185+
*
186+
* @param clock The new {@link Clock} for the copied listener set.
187+
* @return The copied listener set.
188+
*/
189+
@CheckResult
190+
public ListenerSet<T> copy(Clock clock) {
191+
return copy(handler.getLooper(), clock, iterationFinishedEvent);
192+
}
193+
145194
/**
146195
* Copies the listener set.
147196
*
@@ -150,12 +199,13 @@ public ListenerSet<T> copy(Looper looper, IterationFinishedEvent<T> iterationFin
150199
* @param looper The new {@link Looper} for the copied listener set.
151200
* @param clock The new {@link Clock} for the copied listener set.
152201
* @param iterationFinishedEvent The new {@link IterationFinishedEvent} sent when all other events
153-
* sent during one {@link Looper} message queue iteration were handled by the listeners.
202+
* sent during one {@link Looper} message queue iteration were handled by the listeners, or
203+
* null if no such event is needed.
154204
* @return The copied listener set.
155205
*/
156206
@CheckResult
157207
public ListenerSet<T> copy(
158-
Looper looper, Clock clock, IterationFinishedEvent<T> iterationFinishedEvent) {
208+
Looper looper, Clock clock, @Nullable IterationFinishedEvent<T> iterationFinishedEvent) {
159209
return new ListenerSet<>(
160210
listeners, looper, clock, iterationFinishedEvent, throwsWhenUsingWrongThread);
161211
}
@@ -214,8 +264,20 @@ public int size() {
214264
/**
215265
* Adds an event that is sent to the listeners when {@link #flushEvents} is called.
216266
*
217-
* @param eventFlag An integer indicating the type of the event, or {@link C#INDEX_UNSET} to
218-
* report this event without flag.
267+
* <p>This call does not set an integer flag for this event to be reported in the {@link
268+
* IterationFinishedEvent}. Use {@link #queueEvent(int, Event)} instead if this is required.
269+
*
270+
* @param event The event.
271+
*/
272+
public void queueEvent(Event<T> event) {
273+
queueEvent(/* eventFlag= */ C.INDEX_UNSET, event);
274+
}
275+
276+
/**
277+
* Adds an event that is sent to the listeners when {@link #flushEvents} is called.
278+
*
279+
* @param eventFlag An integer indicating the type of the event to be reported in the {@link
280+
* IterationFinishedEvent}, or {@link C#INDEX_UNSET} to report this event without flag.
219281
* @param event The event.
220282
*/
221283
public void queueEvent(int eventFlag, Event<T> event) {
@@ -235,7 +297,7 @@ public void flushEvents() {
235297
if (queuedEvents.isEmpty()) {
236298
return;
237299
}
238-
if (!handler.hasMessages(MSG_ITERATION_FINISHED)) {
300+
if (iterationFinishedEvent != null && !handler.hasMessages(MSG_ITERATION_FINISHED)) {
239301
handler.sendMessageAtFrontOfQueue(handler.obtainMessage(MSG_ITERATION_FINISHED));
240302
}
241303
boolean recursiveFlushInProgress = !flushingEvents.isEmpty();
@@ -251,12 +313,25 @@ public void flushEvents() {
251313
}
252314
}
253315

316+
/**
317+
* {@link #queueEvent(Event) Queues} a single event and immediately {@link #flushEvents() flushes}
318+
* the event queue to notify all listeners.
319+
*
320+
* <p>This call does not set an integer flag for this event to be reported in the {@link
321+
* IterationFinishedEvent}. Use {@link #sendEvent(int, Event)} instead if this is required.
322+
*
323+
* @param event The event.
324+
*/
325+
public void sendEvent(Event<T> event) {
326+
sendEvent(/* eventFlag= */ C.INDEX_UNSET, event);
327+
}
328+
254329
/**
255330
* {@link #queueEvent(int, Event) Queues} a single event and immediately {@link #flushEvents()
256331
* flushes} the event queue to notify all listeners.
257332
*
258-
* @param eventFlag An integer flag indicating the type of the event, or {@link C#INDEX_UNSET} to
259-
* report this event without flag.
333+
* @param eventFlag An integer flag indicating the type of the event to be reported in the {@link
334+
* IterationFinishedEvent}, or {@link C#INDEX_UNSET} to report this event without flag.
260335
* @param event The event.
261336
*/
262337
public void sendEvent(int eventFlag, Event<T> event) {
@@ -294,8 +369,9 @@ public void setThrowsWhenUsingWrongThread(boolean throwsWhenUsingWrongThread) {
294369
}
295370

296371
private boolean handleMessage(Message message) {
372+
IterationFinishedEvent<T> event = checkNotNull(iterationFinishedEvent);
297373
for (ListenerHolder<T> holder : listeners) {
298-
holder.iterationFinished(iterationFinishedEvent);
374+
holder.iterationFinished(event);
299375
if (handler.hasMessages(MSG_ITERATION_FINISHED)) {
300376
// The invocation above triggered new events (and thus scheduled a new message). We need
301377
// to stop here because this new message will take care of informing every listener about
@@ -326,9 +402,9 @@ public ListenerHolder(T listener) {
326402
this.flagsBuilder = new FlagSet.Builder();
327403
}
328404

329-
public void release(IterationFinishedEvent<T> event) {
405+
private void release(@Nullable IterationFinishedEvent<T> event) {
330406
released = true;
331-
if (needsIterationFinishedEvent) {
407+
if (event != null && needsIterationFinishedEvent) {
332408
needsIterationFinishedEvent = false;
333409
event.invoke(listener, flagsBuilder.build());
334410
}

libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/DefaultAnalyticsCollector.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public class DefaultAnalyticsCollector implements AnalyticsCollector {
9090
*/
9191
public DefaultAnalyticsCollector(Clock clock) {
9292
this.clock = checkNotNull(clock);
93-
listeners = new ListenerSet<>(Util.getCurrentOrMainLooper(), clock, (listener, flags) -> {});
93+
listeners = new ListenerSet<>(Util.getCurrentOrMainLooper(), clock);
9494
period = new Period();
9595
window = new Window();
9696
mediaPeriodQueueTracker = new MediaPeriodQueueTracker(period);

libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/preload/BasePreloadManager.java

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import androidx.annotation.CallSuper;
2525
import androidx.annotation.GuardedBy;
2626
import androidx.annotation.Nullable;
27-
import androidx.media3.common.C;
2827
import androidx.media3.common.MediaItem;
2928
import androidx.media3.common.util.Clock;
3029
import androidx.media3.common.util.ListenerSet;
@@ -99,8 +98,7 @@ protected BasePreloadManager(
9998
this.rankingDataComparator = rankingDataComparator;
10099
this.targetPreloadStatusControl = targetPreloadStatusControl;
101100
this.mediaSourceFactory = mediaSourceFactory;
102-
listeners =
103-
new ListenerSet<>(applicationHandler.getLooper(), Clock.DEFAULT, (listener, flags) -> {});
101+
listeners = new ListenerSet<>(applicationHandler.getLooper(), Clock.DEFAULT);
104102
mediaSourceHolderMap = new MediaSourceHolderMap();
105103
this.rankingDataComparator.setInvalidationListener(this::invalidate);
106104
sourceHolderPriorityList = new ArrayList<>();
@@ -361,9 +359,7 @@ protected final void onCompleted(
361359

362360
MediaSourceHolder mediaSourceHolder = checkNotNull(mediaSourceHolderMap.get(mediaSource));
363361
if (shouldNotifyListenerAndAdvancePredicate.apply(targetPreloadStatus)) {
364-
listeners.sendEvent(
365-
/* eventFlag= */ C.INDEX_UNSET,
366-
listener -> listener.onCompleted(mediaSourceHolder.mediaItem));
362+
listeners.sendEvent(listener -> listener.onCompleted(mediaSourceHolder.mediaItem));
367363
maybeAdvanceToNextMediaSourceHolder();
368364
}
369365
});
@@ -382,9 +378,7 @@ protected final void onCompleted(
382378

383379
MediaSourceHolder mediaSourceHolder = checkNotNull(mediaSourceHolderMap.get(mediaItem));
384380
if (shouldNotifyListenerAndAdvancePredicate.apply(targetPreloadStatus)) {
385-
listeners.sendEvent(
386-
/* eventFlag= */ C.INDEX_UNSET,
387-
listener -> listener.onCompleted(mediaSourceHolder.mediaItem));
381+
listeners.sendEvent(listener -> listener.onCompleted(mediaSourceHolder.mediaItem));
388382
maybeAdvanceToNextMediaSourceHolder();
389383
}
390384
});
@@ -404,8 +398,7 @@ protected final void onError(
404398
}
405399

406400
if (shouldNotifyListenerAndAdvancePredicate.apply(targetPreloadStatus)) {
407-
listeners.sendEvent(
408-
/* eventFlag= */ C.INDEX_UNSET, listener -> listener.onError(error));
401+
listeners.sendEvent(listener -> listener.onError(error));
409402
maybeAdvanceToNextMediaSourceHolder();
410403
}
411404
});
@@ -425,8 +418,7 @@ protected final void onError(
425418
}
426419

427420
if (shouldNotifyListenerAndAdvancePredicate.apply(targetPreloadStatus)) {
428-
listeners.sendEvent(
429-
/* eventFlag= */ C.INDEX_UNSET, listener -> listener.onError(error));
421+
listeners.sendEvent(listener -> listener.onError(error));
430422
maybeAdvanceToNextMediaSourceHolder();
431423
}
432424
});

libraries/transformer/src/main/java/androidx/media3/transformer/FallbackListener.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import static com.google.common.base.Preconditions.checkState;
2020

2121
import androidx.annotation.IntRange;
22-
import androidx.media3.common.C;
2322
import androidx.media3.common.util.HandlerWrapper;
2423
import androidx.media3.common.util.ListenerSet;
2524
import java.util.Objects;
@@ -117,7 +116,6 @@ public synchronized void onTransformationRequestFinalized(
117116
transformerListenerHandler.post(
118117
() ->
119118
transformerListeners.sendEvent(
120-
/* eventFlag= */ C.INDEX_UNSET,
121119
listener ->
122120
listener.onFallbackApplied(
123121
composition,

libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ public Builder(Context context) {
159159
looper = Util.getCurrentOrMainLooper();
160160
debugViewProvider = DebugViewProvider.NONE;
161161
clock = Clock.DEFAULT;
162-
listeners = new ListenerSet<>(looper, clock, (listener, flags) -> {});
162+
listeners = new ListenerSet<>(looper, clock);
163163
if (SDK_INT >= 35) {
164164
usePlatformDiagnostics = true;
165165
metricsReporterFactory =
@@ -540,7 +540,7 @@ public Builder setMuxerFactory(Muxer.Factory muxerFactory) {
540540
@CanIgnoreReturnValue
541541
public Builder setLooper(Looper looper) {
542542
this.looper = looper;
543-
this.listeners = listeners.copy(looper, (listener, flags) -> {});
543+
this.listeners = listeners.copy(looper);
544544
return this;
545545
}
546546

@@ -573,7 +573,7 @@ public Builder setDebugViewProvider(DebugViewProvider debugViewProvider) {
573573
@VisibleForTesting
574574
public Builder setClock(Clock clock) {
575575
this.clock = clock;
576-
this.listeners = listeners.copy(looper, clock, (listener, flags) -> {});
576+
this.listeners = listeners.copy(clock);
577577
return this;
578578
}
579579

@@ -1773,10 +1773,7 @@ private void startInternal(
17731773
private void onExportCompletedWithSuccess() {
17741774
maybeStopExportWatchdogTimer();
17751775
ExportResult exportResult = exportResultBuilder.build();
1776-
listeners.queueEvent(
1777-
/* eventFlag= */ C.INDEX_UNSET,
1778-
listener -> listener.onCompleted(checkNotNull(composition), exportResult));
1779-
listeners.flushEvents();
1776+
listeners.sendEvent(listener -> listener.onCompleted(checkNotNull(composition), exportResult));
17801777
if (canCollectEditingMetrics()) {
17811778
checkNotNull(editingMetricsCollector).onExportSuccess(exportResult, isExportResumed());
17821779
}
@@ -1786,10 +1783,8 @@ private void onExportCompletedWithSuccess() {
17861783
private void onExportCompletedWithError(ExportException exception) {
17871784
maybeStopExportWatchdogTimer();
17881785
ExportResult exportResult = exportResultBuilder.build();
1789-
listeners.queueEvent(
1790-
/* eventFlag= */ C.INDEX_UNSET,
1786+
listeners.sendEvent(
17911787
listener -> listener.onError(checkNotNull(composition), exportResult, exception));
1792-
listeners.flushEvents();
17931788
if (canCollectEditingMetrics()) {
17941789
ProgressHolder progressHolder = new ProgressHolder();
17951790
int progressState = getProgress(progressHolder);

libraries/transformer/src/test/java/androidx/media3/transformer/FallbackListenerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ private static ListenerSet<Transformer.Listener> createListenerSet(
151151
}
152152

153153
private static ListenerSet<Transformer.Listener> createListenerSet() {
154-
return new ListenerSet<>(Looper.myLooper(), Clock.DEFAULT, (listener, flags) -> {});
154+
return new ListenerSet<>(Looper.myLooper(), Clock.DEFAULT);
155155
}
156156

157157
private static HandlerWrapper createHandler() {

libraries/transformer/src/test/java/androidx/media3/transformer/VideoEncoderWrapperTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public final class VideoEncoderWrapperTest {
6464
private final FallbackListener fallbackListener =
6565
new FallbackListener(
6666
FAKE_COMPOSITION,
67-
new ListenerSet<>(Looper.myLooper(), Clock.DEFAULT, (listener, flags) -> {}),
67+
new ListenerSet<>(Looper.myLooper(), Clock.DEFAULT),
6868
Clock.DEFAULT.createHandler(Looper.myLooper(), /* callback= */ null),
6969
emptyTransformationRequest);
7070
private final VideoSampleExporter.EncoderWrapper encoderWrapper =

0 commit comments

Comments
 (0)