ExoPlayer.Builder: lazily initialize default components

Initialize default components lazily in ExoPlayer.Builder to avoid
redundant component instantiations, useful in cases where apps
overwrite default components with ExoPlayer.Builder setters.

The fields in ExoPlayer.Builder are wrapped in a Supplier (rather than
just making then nullable and initializing them in
ExoPlayer.Builder.build()) so that we maintain the proguarding
properties of this class. The exception is
ExoPlayer.Builder.AnalyticsCollector which became nullable and is
initialized in ExoPlayer.Builder.build() in order to use any Clock
that has been set separately with ExoPlayer.Builder.setClock().

#minor-release

PiperOrigin-RevId: 406345976
This commit is contained in:
christosts 2021-10-29 13:31:12 +00:00 committed by tonihei
parent 8acce1b5c2
commit a0f8ac7503
2 changed files with 90 additions and 55 deletions

View File

@ -16,6 +16,7 @@
package com.google.android.exoplayer2; package com.google.android.exoplayer2;
import static com.google.android.exoplayer2.util.Assertions.checkArgument; import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Assertions.checkState; import static com.google.android.exoplayer2.util.Assertions.checkState;
import android.content.Context; import android.content.Context;
@ -59,6 +60,7 @@ import com.google.android.exoplayer2.video.MediaCodecVideoRenderer;
import com.google.android.exoplayer2.video.VideoFrameMetadataListener; import com.google.android.exoplayer2.video.VideoFrameMetadataListener;
import com.google.android.exoplayer2.video.VideoSize; import com.google.android.exoplayer2.video.VideoSize;
import com.google.android.exoplayer2.video.spherical.CameraMotionListener; import com.google.android.exoplayer2.video.spherical.CameraMotionListener;
import com.google.common.base.Supplier;
import java.util.List; import java.util.List;
/** /**
@ -366,12 +368,12 @@ public interface ExoPlayer extends Player {
/* package */ Clock clock; /* package */ Clock clock;
/* package */ long foregroundModeTimeoutMs; /* package */ long foregroundModeTimeoutMs;
/* package */ RenderersFactory renderersFactory; /* package */ Supplier<RenderersFactory> renderersFactorySupplier;
/* package */ MediaSourceFactory mediaSourceFactory; /* package */ Supplier<MediaSourceFactory> mediaSourceFactorySupplier;
/* package */ TrackSelector trackSelector; /* package */ Supplier<TrackSelector> trackSelectorSupplier;
/* package */ LoadControl loadControl; /* package */ Supplier<LoadControl> loadControlSupplier;
/* package */ BandwidthMeter bandwidthMeter; /* package */ Supplier<BandwidthMeter> bandwidthMeterSupplier;
/* package */ AnalyticsCollector analyticsCollector; /* package */ Supplier<AnalyticsCollector> analyticsCollectorSupplier;
/* package */ Looper looper; /* package */ Looper looper;
@Nullable /* package */ PriorityTaskManager priorityTaskManager; @Nullable /* package */ PriorityTaskManager priorityTaskManager;
/* package */ AudioAttributes audioAttributes; /* package */ AudioAttributes audioAttributes;
@ -437,8 +439,8 @@ public interface ExoPlayer extends Player {
public Builder(Context context) { public Builder(Context context) {
this( this(
context, context,
new DefaultRenderersFactory(context), () -> new DefaultRenderersFactory(context),
new DefaultMediaSourceFactory(context, new DefaultExtractorsFactory())); () -> new DefaultMediaSourceFactory(context, new DefaultExtractorsFactory()));
} }
/** /**
@ -456,8 +458,8 @@ public interface ExoPlayer extends Player {
public Builder(Context context, RenderersFactory renderersFactory) { public Builder(Context context, RenderersFactory renderersFactory) {
this( this(
context, context,
renderersFactory, () -> renderersFactory,
new DefaultMediaSourceFactory(context, new DefaultExtractorsFactory())); () -> new DefaultMediaSourceFactory(context, new DefaultExtractorsFactory()));
} }
/** /**
@ -474,7 +476,7 @@ public interface ExoPlayer extends Player {
* MediaItem}. * MediaItem}.
*/ */
public Builder(Context context, MediaSourceFactory mediaSourceFactory) { public Builder(Context context, MediaSourceFactory mediaSourceFactory) {
this(context, new DefaultRenderersFactory(context), mediaSourceFactory); this(context, () -> new DefaultRenderersFactory(context), () -> mediaSourceFactory);
} }
/** /**
@ -494,14 +496,7 @@ public interface ExoPlayer extends Player {
*/ */
public Builder( public Builder(
Context context, RenderersFactory renderersFactory, MediaSourceFactory mediaSourceFactory) { Context context, RenderersFactory renderersFactory, MediaSourceFactory mediaSourceFactory) {
this( this(context, () -> renderersFactory, () -> mediaSourceFactory);
context,
renderersFactory,
mediaSourceFactory,
new DefaultTrackSelector(context),
new DefaultLoadControl(),
DefaultBandwidthMeter.getSingletonInstance(context),
new AnalyticsCollector(Clock.DEFAULT));
} }
/** /**
@ -527,13 +522,48 @@ public interface ExoPlayer extends Player {
LoadControl loadControl, LoadControl loadControl,
BandwidthMeter bandwidthMeter, BandwidthMeter bandwidthMeter,
AnalyticsCollector analyticsCollector) { AnalyticsCollector analyticsCollector) {
this(
context,
() -> renderersFactory,
() -> mediaSourceFactory,
() -> trackSelector,
() -> loadControl,
() -> bandwidthMeter,
() -> analyticsCollector);
}
private Builder(
Context context,
Supplier<RenderersFactory> renderersFactorySupplier,
Supplier<MediaSourceFactory> mediaSourceFactorySupplier) {
this(
context,
renderersFactorySupplier,
mediaSourceFactorySupplier,
() -> new DefaultTrackSelector(context),
DefaultLoadControl::new,
() -> DefaultBandwidthMeter.getSingletonInstance(context),
/* analyticsCollectorSupplier= */ null);
}
private Builder(
Context context,
Supplier<RenderersFactory> renderersFactorySupplier,
Supplier<MediaSourceFactory> mediaSourceFactorySupplier,
Supplier<TrackSelector> trackSelectorSupplier,
Supplier<LoadControl> loadControlSupplier,
Supplier<BandwidthMeter> bandwidthMeterSupplier,
@Nullable Supplier<AnalyticsCollector> analyticsCollectorSupplier) {
this.context = context; this.context = context;
this.renderersFactory = renderersFactory; this.renderersFactorySupplier = renderersFactorySupplier;
this.mediaSourceFactory = mediaSourceFactory; this.mediaSourceFactorySupplier = mediaSourceFactorySupplier;
this.trackSelector = trackSelector; this.trackSelectorSupplier = trackSelectorSupplier;
this.loadControl = loadControl; this.loadControlSupplier = loadControlSupplier;
this.bandwidthMeter = bandwidthMeter; this.bandwidthMeterSupplier = bandwidthMeterSupplier;
this.analyticsCollector = analyticsCollector; this.analyticsCollectorSupplier =
analyticsCollectorSupplier != null
? analyticsCollectorSupplier
: () -> new AnalyticsCollector(checkNotNull(clock));
looper = Util.getCurrentOrMainLooper(); looper = Util.getCurrentOrMainLooper();
audioAttributes = AudioAttributes.DEFAULT; audioAttributes = AudioAttributes.DEFAULT;
wakeMode = C.WAKE_MODE_NONE; wakeMode = C.WAKE_MODE_NONE;
@ -573,7 +603,7 @@ public interface ExoPlayer extends Player {
*/ */
public Builder setRenderersFactory(RenderersFactory renderersFactory) { public Builder setRenderersFactory(RenderersFactory renderersFactory) {
checkState(!buildCalled); checkState(!buildCalled);
this.renderersFactory = renderersFactory; this.renderersFactorySupplier = () -> renderersFactory;
return this; return this;
} }
@ -586,7 +616,7 @@ public interface ExoPlayer extends Player {
*/ */
public Builder setMediaSourceFactory(MediaSourceFactory mediaSourceFactory) { public Builder setMediaSourceFactory(MediaSourceFactory mediaSourceFactory) {
checkState(!buildCalled); checkState(!buildCalled);
this.mediaSourceFactory = mediaSourceFactory; this.mediaSourceFactorySupplier = () -> mediaSourceFactory;
return this; return this;
} }
@ -599,7 +629,7 @@ public interface ExoPlayer extends Player {
*/ */
public Builder setTrackSelector(TrackSelector trackSelector) { public Builder setTrackSelector(TrackSelector trackSelector) {
checkState(!buildCalled); checkState(!buildCalled);
this.trackSelector = trackSelector; this.trackSelectorSupplier = () -> trackSelector;
return this; return this;
} }
@ -612,7 +642,7 @@ public interface ExoPlayer extends Player {
*/ */
public Builder setLoadControl(LoadControl loadControl) { public Builder setLoadControl(LoadControl loadControl) {
checkState(!buildCalled); checkState(!buildCalled);
this.loadControl = loadControl; this.loadControlSupplier = () -> loadControl;
return this; return this;
} }
@ -625,7 +655,7 @@ public interface ExoPlayer extends Player {
*/ */
public Builder setBandwidthMeter(BandwidthMeter bandwidthMeter) { public Builder setBandwidthMeter(BandwidthMeter bandwidthMeter) {
checkState(!buildCalled); checkState(!buildCalled);
this.bandwidthMeter = bandwidthMeter; this.bandwidthMeterSupplier = () -> bandwidthMeter;
return this; return this;
} }
@ -652,7 +682,7 @@ public interface ExoPlayer extends Player {
*/ */
public Builder setAnalyticsCollector(AnalyticsCollector analyticsCollector) { public Builder setAnalyticsCollector(AnalyticsCollector analyticsCollector) {
checkState(!buildCalled); checkState(!buildCalled);
this.analyticsCollector = analyticsCollector; this.analyticsCollectorSupplier = () -> analyticsCollector;
return this; return this;
} }

View File

@ -28,6 +28,7 @@ import static com.google.android.exoplayer2.Renderer.MSG_SET_SKIP_SILENCE_ENABLE
import static com.google.android.exoplayer2.Renderer.MSG_SET_VIDEO_FRAME_METADATA_LISTENER; import static com.google.android.exoplayer2.Renderer.MSG_SET_VIDEO_FRAME_METADATA_LISTENER;
import static com.google.android.exoplayer2.Renderer.MSG_SET_VIDEO_OUTPUT; import static com.google.android.exoplayer2.Renderer.MSG_SET_VIDEO_OUTPUT;
import static com.google.android.exoplayer2.Renderer.MSG_SET_VOLUME; import static com.google.android.exoplayer2.Renderer.MSG_SET_VOLUME;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import android.content.Context; import android.content.Context;
import android.graphics.Rect; import android.graphics.Rect;
@ -66,7 +67,6 @@ import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters; import com.google.android.exoplayer2.trackselection.TrackSelectionParameters;
import com.google.android.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.ConditionVariable; import com.google.android.exoplayer2.util.ConditionVariable;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
@ -409,12 +409,14 @@ public class SimpleExoPlayer extends BasePlayer
Clock clock, Clock clock,
Looper applicationLooper) { Looper applicationLooper) {
this( this(
new ExoPlayer.Builder(context, renderersFactory) new ExoPlayer.Builder(
.setTrackSelector(trackSelector) context,
.setMediaSourceFactory(mediaSourceFactory) renderersFactory,
.setLoadControl(loadControl) mediaSourceFactory,
.setBandwidthMeter(bandwidthMeter) trackSelector,
.setAnalyticsCollector(analyticsCollector) loadControl,
bandwidthMeter,
analyticsCollector)
.setUseLazyPreparation(useLazyPreparation) .setUseLazyPreparation(useLazyPreparation)
.setClock(clock) .setClock(clock)
.setLooper(applicationLooper)); .setLooper(applicationLooper));
@ -431,7 +433,7 @@ public class SimpleExoPlayer extends BasePlayer
constructorFinished = new ConditionVariable(); constructorFinished = new ConditionVariable();
try { try {
applicationContext = builder.context.getApplicationContext(); applicationContext = builder.context.getApplicationContext();
analyticsCollector = builder.analyticsCollector; analyticsCollector = builder.analyticsCollectorSupplier.get();
priorityTaskManager = builder.priorityTaskManager; priorityTaskManager = builder.priorityTaskManager;
audioAttributes = builder.audioAttributes; audioAttributes = builder.audioAttributes;
videoScalingMode = builder.videoScalingMode; videoScalingMode = builder.videoScalingMode;
@ -443,12 +445,15 @@ public class SimpleExoPlayer extends BasePlayer
listeners = new CopyOnWriteArraySet<>(); listeners = new CopyOnWriteArraySet<>();
Handler eventHandler = new Handler(builder.looper); Handler eventHandler = new Handler(builder.looper);
renderers = renderers =
builder.renderersFactory.createRenderers( builder
eventHandler, .renderersFactorySupplier
componentListener, .get()
componentListener, .createRenderers(
componentListener, eventHandler,
componentListener); componentListener,
componentListener,
componentListener,
componentListener);
// Set initial values. // Set initial values.
volume = 1; volume = 1;
@ -476,10 +481,10 @@ public class SimpleExoPlayer extends BasePlayer
player = player =
new ExoPlayerImpl( new ExoPlayerImpl(
renderers, renderers,
builder.trackSelector, builder.trackSelectorSupplier.get(),
builder.mediaSourceFactory, builder.mediaSourceFactorySupplier.get(),
builder.loadControl, builder.loadControlSupplier.get(),
builder.bandwidthMeter, builder.bandwidthMeterSupplier.get(),
analyticsCollector, analyticsCollector,
builder.useLazyPreparation, builder.useLazyPreparation,
builder.seekParameters, builder.seekParameters,
@ -848,7 +853,7 @@ public class SimpleExoPlayer extends BasePlayer
@Override @Override
public void addAnalyticsListener(AnalyticsListener listener) { public void addAnalyticsListener(AnalyticsListener listener) {
// Don't verify application thread. We allow calls to this method from any thread. // Don't verify application thread. We allow calls to this method from any thread.
Assertions.checkNotNull(listener); checkNotNull(listener);
analyticsCollector.addListener(listener); analyticsCollector.addListener(listener);
} }
@ -874,7 +879,7 @@ public class SimpleExoPlayer extends BasePlayer
return; return;
} }
if (isPriorityTaskManagerRegistered) { if (isPriorityTaskManagerRegistered) {
Assertions.checkNotNull(this.priorityTaskManager).remove(C.PRIORITY_PLAYBACK); checkNotNull(this.priorityTaskManager).remove(C.PRIORITY_PLAYBACK);
} }
if (priorityTaskManager != null && isLoading()) { if (priorityTaskManager != null && isLoading()) {
priorityTaskManager.add(C.PRIORITY_PLAYBACK); priorityTaskManager.add(C.PRIORITY_PLAYBACK);
@ -982,7 +987,7 @@ public class SimpleExoPlayer extends BasePlayer
@Override @Override
public void addListener(Listener listener) { public void addListener(Listener listener) {
Assertions.checkNotNull(listener); checkNotNull(listener);
listeners.add(listener); listeners.add(listener);
EventListener eventListener = listener; EventListener eventListener = listener;
addListener(eventListener); addListener(eventListener);
@ -992,13 +997,13 @@ public class SimpleExoPlayer extends BasePlayer
@Override @Override
public void addListener(Player.EventListener listener) { public void addListener(Player.EventListener listener) {
// Don't verify application thread. We allow calls to this method from any thread. // Don't verify application thread. We allow calls to this method from any thread.
Assertions.checkNotNull(listener); checkNotNull(listener);
player.addEventListener(listener); player.addEventListener(listener);
} }
@Override @Override
public void removeListener(Listener listener) { public void removeListener(Listener listener) {
Assertions.checkNotNull(listener); checkNotNull(listener);
listeners.remove(listener); listeners.remove(listener);
EventListener eventListener = listener; EventListener eventListener = listener;
removeListener(eventListener); removeListener(eventListener);
@ -1322,7 +1327,7 @@ public class SimpleExoPlayer extends BasePlayer
ownedSurface = null; ownedSurface = null;
} }
if (isPriorityTaskManagerRegistered) { if (isPriorityTaskManagerRegistered) {
Assertions.checkNotNull(priorityTaskManager).remove(C.PRIORITY_PLAYBACK); checkNotNull(priorityTaskManager).remove(C.PRIORITY_PLAYBACK);
isPriorityTaskManagerRegistered = false; isPriorityTaskManagerRegistered = false;
} }
currentCues = Collections.emptyList(); currentCues = Collections.emptyList();