Playlist

L'API Playlist viene definita dall'interfaccia Player, implementata da tutte le implementazioni ExoPlayer. Le playlist consentono la riproduzione sequenziale di più contenuti multimediali. L'esempio seguente mostra come avviare la riproduzione di una playlist contenente due video:

Kotlin

// Build the media items.
val firstItem = MediaItem.fromUri(firstVideoUri)
val secondItem = MediaItem.fromUri(secondVideoUri)
// Add the media items to be played.
player.addMediaItem(firstItem)
player.addMediaItem(secondItem)
// Prepare the player.
player.prepare()
// Start the playback.
player.play()

Java

// Build the media items.
MediaItem firstItem = MediaItem.fromUri(firstVideoUri);
MediaItem secondItem = MediaItem.fromUri(secondVideoUri);
// Add the media items to be played.
player.addMediaItem(firstItem);
player.addMediaItem(secondItem);
// Prepare the player.
player.prepare();
// Start the playback.
player.play();

Le transizioni tra gli elementi di una playlist avvengono in maniera fluida. Non è necessario che siano dello stesso formato (ad esempio, è consentito che una playlist contenga sia video H264 che VP9). Possono anche essere di tipi diversi (ovvero, non è un problema se una playlist contiene video, immagini e stream solo audio). Puoi utilizzare lo stesso MediaItem più volte all'interno di una playlist.

Modificare la playlist

Puoi modificare in modo dinamico una playlist aggiungendo, spostando, rimuovendo o sostituendo gli elementi multimediali. Questa operazione può essere eseguita prima e durante la riproduzione chiamando i metodi dell'API playlist corrispondenti:

Kotlin

// Adds a media item at position 1 in the playlist.
player.addMediaItem(/* index= */ 1, MediaItem.fromUri(thirdUri))
// Moves the third media item from position 2 to the start of the playlist.
player.moveMediaItem(/* currentIndex= */ 2, /* newIndex= */ 0)
// Removes the first item from the playlist.
player.removeMediaItem(/* index= */ 0)
// Replace the second item in the playlist.
player.replaceMediaItem(/* index= */ 1, MediaItem.fromUri(newUri))

Java

// Adds a media item at position 1 in the playlist.
player.addMediaItem(/* index= */ 1, MediaItem.fromUri(thirdUri));
// Moves the third media item from position 2 to the start of the playlist.
player.moveMediaItem(/* currentIndex= */ 2, /* newIndex= */ 0);
// Removes the first item from the playlist.
player.removeMediaItem(/* index= */ 0);
// Replace the second item in the playlist.
player.replaceMediaItem(/* index= */ 1, MediaItem.fromUri(newUri));

Sono supportate anche la sostituzione e l'eliminazione dell'intera playlist:

Kotlin

// Replaces the playlist with a new one.
val newItems: List<MediaItem> = listOf(MediaItem.fromUri(fourthUri), MediaItem.fromUri(fifthUri))
player.setMediaItems(newItems, /* resetPosition= */ true)
// Clears the playlist. If prepared, the player transitions to the ended state.
player.clearMediaItems()

Java

// Replaces the playlist with a new one.
ImmutableList<MediaItem> newItems =
    ImmutableList.of(MediaItem.fromUri(fourthUri), MediaItem.fromUri(fifthUri));
player.setMediaItems(newItems, /* resetPosition= */ true);
// Clears the playlist. If prepared, the player transitions to the ended state.
player.clearMediaItems();

Il player gestisce automaticamente le modifiche durante la riproduzione nel modo corretto:

  • Se il MediaItem attualmente in riproduzione viene spostato, la riproduzione non viene interrotta e il suo nuovo successore verrà riprodotto al termine.
  • Se l'elemento MediaItem in riproduzione viene rimosso, il player riprodurrà automaticamente il primo successore rimanente o passerà allo stato "Terminata" se non esiste un successore di questo tipo.
  • Se il MediaItem attualmente in riproduzione viene sostituito, la riproduzione non viene interrotta se nessuna delle proprietà del MediaItem pertinenti per la riproduzione è stata modificata. Ad esempio, nella maggior parte dei casi è possibile aggiornare i campi MediaItem.MediaMetadata senza influire sulla riproduzione.

Esecuzione di query sulla playlist

È possibile eseguire query sulla playlist utilizzando Player.getMediaItemCount e Player.getMediaItemAt. È possibile eseguire query sull'elemento multimediale attualmente in riproduzione chiamando Player.getCurrentMediaItem. Esistono anche altri metodi di navigazione comodi, come Player.hasNextMediaItem o Player.getNextMediaItemIndex, per semplificare la navigazione nella playlist.

Modalità di ripetizione

Il player supporta tre modalità di ripetizione che possono essere impostate in qualsiasi momento con Player.setRepeatMode:

  • Player.REPEAT_MODE_OFF: la playlist non viene ripetuta e il player passerà a Player.STATE_ENDED dopo la riproduzione dell'ultimo elemento della playlist.
  • Player.REPEAT_MODE_ONE: l'elemento corrente viene ripetuto in un loop infinito. Metodi come Player.seekToNextMediaItem lo ignoreranno e cercheranno l'elemento successivo nell'elenco, che verrà poi ripetuto in un ciclo infinito.
  • Player.REPEAT_MODE_ALL: l'intera playlist viene ripetuta in un loop infinito.

Riproduzione casuale

La modalità Shuffle può essere attivata o disattivata in qualsiasi momento con Player.setShuffleModeEnabled. In modalità di riproduzione casuale, il player riprodurrà la playlist in un ordine precalcolato e casuale. Tutti gli elementi verranno riprodotti una volta e la modalità di riproduzione casuale può essere combinata anche con Player.REPEAT_MODE_ALL per ripetere lo stesso ordine casuale in un loop infinito. Quando la modalità di riproduzione casuale è disattivata, la riproduzione riprende dall'elemento corrente nella sua posizione originale nella playlist.

Tieni presente che gli indici restituiti da metodi come Player.getCurrentMediaItemIndex fanno sempre riferimento all'ordine originale, non mischiato. Allo stesso modo, Player.seekToNextMediaItem non riprodurrà l'elemento al minuto player.getCurrentMediaItemIndex() + 1, ma l'elemento successivo in base all'ordine di riproduzione casuale. L'inserimento di nuovi elementi nella playlist o la rimozione di elementi manterrà immutato l'ordine in riproduzione casuale esistente, per quanto possibile.

Impostazione di un ordine casuale personalizzato

Per impostazione predefinita, il player supporta la riproduzione casuale mediante DefaultShuffleOrder. Questo può essere personalizzato fornendo un'implementazione dell'ordine casuale personalizzato o impostando un ordine personalizzato nel costruttore DefaultShuffleOrder:

Kotlin

// Set a custom shuffle order for the 5 items currently in the playlist:
exoPlayer.setShuffleOrder(DefaultShuffleOrder(intArrayOf(3, 1, 0, 4, 2), randomSeed))
// Enable shuffle mode.
exoPlayer.shuffleModeEnabled = true

Java

// Set a custom shuffle order for the 5 items currently in the playlist:
exoPlayer.setShuffleOrder(new DefaultShuffleOrder(new int[] {3, 1, 0, 4, 2}, randomSeed));
// Enable shuffle mode.
exoPlayer.setShuffleModeEnabled(/* shuffleModeEnabled= */ true);

Identificazione degli elementi della playlist

Per identificare gli elementi della playlist, puoi impostare MediaItem.mediaId durante lo sviluppo dell'elemento:

Kotlin

// Build a media item with a media ID.
val mediaItem = MediaItem.Builder().setUri(uri).setMediaId(mediaId).build()

Java

// Build a media item with a media ID.
MediaItem mediaItem = new MediaItem.Builder().setUri(uri).setMediaId(mediaId).build();

Se un'app non definisce esplicitamente un ID media per un elemento multimediale, viene utilizzata la rappresentazione di stringa dell'URI.

Associare i dati dell'app agli elementi della playlist

Oltre a un ID, ogni elemento multimediale può essere configurato anche con un tag personalizzato, che può essere qualsiasi oggetto fornito dall'app. Un utilizzo dei tag personalizzati è l'associazione di metadati a ogni elemento multimediale:

Kotlin

// Build a media item with a custom tag.
val mediaItem = MediaItem.Builder().setUri(uri).setTag(metadata).build()

Java

// Build a media item with a custom tag.
MediaItem mediaItem = new MediaItem.Builder().setUri(uri).setTag(metadata).build();

Rilevamento del momento in cui la riproduzione passa a un altro elemento multimediale

Quando la riproduzione passa a un altro elemento multimediale o inizia a ripetere lo stesso elemento multimediale, viene chiamato Listener.onMediaItemTransition(MediaItem, @MediaItemTransitionReason). Questo callback riceve il nuovo elemento multimediale, insieme a un @MediaItemTransitionReason che indica il motivo della transizione. Un caso d'uso comune per onMediaItemTransition è aggiornare l'interfaccia utente dell'app per il nuovo elemento multimediale:

Kotlin

override fun onMediaItemTransition(
  mediaItem: MediaItem?,
  @MediaItemTransitionReason reason: Int,
) {
  updateUiForPlayingMediaItem(mediaItem)
}

Java

@Override
public void onMediaItemTransition(
    @Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {
  updateUiForPlayingMediaItem(mediaItem);
}

Se i metadati necessari per aggiornare l'interfaccia utente sono associati a ogni elemento multimediale utilizzando tag personalizzati, un'implementazione potrebbe essere simile alla seguente:

Kotlin

override fun onMediaItemTransition(
  mediaItem: MediaItem?,
  @MediaItemTransitionReason reason: Int,
) {
  var metadata: CustomMetadata? = null
  mediaItem?.localConfiguration?.let { localConfiguration ->
    metadata = localConfiguration.tag as? CustomMetadata
  }
  updateUiForPlayingMediaItem(metadata)
}

Java

@Override
public void onMediaItemTransition(
    @Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {
  @Nullable CustomMetadata metadata = null;
  if (mediaItem != null && mediaItem.localConfiguration != null) {
    metadata = (CustomMetadata) mediaItem.localConfiguration.tag;
  }
  updateUiForPlayingMediaItem(metadata);
}

Rilevamento delle modifiche alla playlist

Quando un elemento multimediale viene aggiunto, rimosso o spostato, Listener.onTimelineChanged(Timeline, @TimelineChangeReason) viene chiamato immediatamente con TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED. Questo callback viene chiamato anche quando il player non è stato ancora preparato.

Kotlin

override fun onTimelineChanged(timeline: Timeline, @TimelineChangeReason reason: Int) {
  if (reason == Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED) {
    // Update the UI according to the modified playlist (add, move or remove).
    updateUiForPlaylist(timeline)
  }
}

Java

@Override
public void onTimelineChanged(Timeline timeline, @TimelineChangeReason int reason) {
  if (reason == TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED) {
    // Update the UI according to the modified playlist (add, move or remove).
    updateUiForPlaylist(timeline);
  }
}

Quando diventano disponibili informazioni come la durata di un elemento multimediale nella playlist, Timeline viene aggiornato e onTimelineChanged viene chiamato con TIMELINE_CHANGE_REASON_SOURCE_UPDATE. Altri motivi che possono causare un aggiornamento della sequenza temporale includono:

  • Un manifest diventa disponibile dopo la preparazione di un elemento multimediale adattivo.
  • Un file manifest aggiornato periodicamente durante la riproduzione di un live streaming.