Playlists

Die Playlist API wird durch die Player-Schnittstelle definiert, die von allen ExoPlayer-Implementierungen implementiert wird. Playlists ermöglichen die sequenzielle Wiedergabe mehrerer Medieninhalte. Im folgenden Beispiel wird gezeigt, wie die Wiedergabe einer Playlist mit zwei Videos gestartet wird:

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();

Die Übergänge zwischen den Elementen in einer Playlist sind nahtlos. Es muss nicht dasselbe Format verwendet werden. Eine Playlist kann beispielsweise sowohl H264- als auch VP9-Videos enthalten. Sie können sogar verschiedener Art sein. Das heißt, eine Playlist kann Videos, Bilder und Streams mit reiner Audiowiedergabe enthalten. Du kannst dieselbe MediaItem innerhalb einer Playlist mehrmals verwenden.

Playlist ändern

Du kannst eine Playlist dynamisch ändern, indem du Medienelemente hinzufügst, verschiebst, entfernst oder ersetzt. Das ist sowohl vor als auch während der Wiedergabe möglich. Rufe dazu die entsprechenden Playlist API-Methoden auf:

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));

Es wird auch unterstützt, die gesamte Playlist zu ersetzen und zu löschen:

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();

Im Player werden Änderungen während der Wiedergabe automatisch richtig verarbeitet:

  • Wenn die aktuell wiedergegebene MediaItem verschoben wird, wird die Wiedergabe nicht unterbrochen und der neue Nachfolger wird nach dem Ende abgespielt.
  • Wenn der aktuell wiedergegebene MediaItem entfernt wird, spielt der Spieler automatisch den ersten verbleibenden Nachfolger ab. Ist kein Nachfolger vorhanden, wechselt er in den Status „Beendet“.
  • Wenn das aktuell wiedergegebene MediaItem ersetzt wird, wird die Wiedergabe nicht unterbrochen, falls keine der für die Wiedergabe relevanten Eigenschaften in MediaItem geändert wird. So ist es beispielsweise möglich, die MediaItem.MediaMetadata-Felder in den meisten Fällen zu aktualisieren, ohne die Wiedergabe zu beeinträchtigen.

Playlist abfragen

Die Playlist kann mit Player.getMediaItemCount und Player.getMediaItemAt abgefragt werden. Das aktuell wiedergegebene Medienelement kann durch Aufrufen von Player.getCurrentMediaItem abgefragt werden. Es gibt auch andere praktische Methoden wie Player.hasNextMediaItem oder Player.getNextMediaItemIndex, um die Navigation in der Playlist zu vereinfachen.

Wiederholungsmodi

Der Player unterstützt drei Wiederholungsmodi, die jederzeit mit Player.setRepeatMode festgelegt werden können:

  • Player.REPEAT_MODE_OFF: Die Playlist wird nicht wiederholt und der Player wechselt zu Player.STATE_ENDED, sobald der letzte Titel in der Playlist abgespielt wurde.
  • Player.REPEAT_MODE_ONE: Das aktuelle Element wird in einer Endlosschleife wiederholt. Methoden wie Player.seekToNextMediaItem ignorieren dies und springen zum nächsten Element in der Liste, das dann in einer Endlosschleife wiederholt wird.
  • Player.REPEAT_MODE_ALL: Die gesamte Playlist wird in einer Endlosschleife wiederholt.

Zufallsmix

Der Shuffle-Modus kann jederzeit mit Player.setShuffleModeEnabled aktiviert oder deaktiviert werden. Im Zufallsmix spielt der Player die Playlist in einer vorausberechneten, zufälligen Reihenfolge ab. Alle Elemente werden einmal abgespielt und der Zufallsmix kann auch mit Player.REPEAT_MODE_ALL kombiniert werden, um dieselbe zufällige Reihenfolge in einer Endlosschleife zu wiederholen. Wenn der Zufallsmix deaktiviert ist, wird die Wiedergabe ab dem aktuellen Element an seiner ursprünglichen Position in der Playlist fortgesetzt.

Die Indizes, die von Methoden wie Player.getCurrentMediaItemIndex zurückgegeben werden, beziehen sich immer auf die ursprüngliche, nicht zufällige Reihenfolge. Wenn du Player.seekToNextMediaItem drückst, wird nicht das Element an player.getCurrentMediaItemIndex() + 1 abgespielt, sondern das nächste Element gemäß der Zufallsmixreihenfolge. Wenn du neue Elemente in die Playlist einfügst oder Elemente entfernst, bleibt die vorhandene Zufallsmix-Reihenfolge nach Möglichkeit unverändert.

Benutzerdefinierte Zufallsmixreihenfolge festlegen

Standardmäßig unterstützt der Player das Zufallsmixen mit der Taste DefaultShuffleOrder. Das kann angepasst werden, indem eine benutzerdefinierte Zufallsmixreihenfolge implementiert oder eine benutzerdefinierte Reihenfolge im Konstruktor von DefaultShuffleOrder festgelegt wird:

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);

Playlist-Elemente identifizieren

Um Playlist-Elemente zu identifizieren, kann MediaItem.mediaId beim Erstellen des Elements festgelegt werden:

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();

Wenn eine App keine Medien-ID für ein Medienelement explizit definiert, wird die Stringdarstellung des URI verwendet.

App-Daten mit Playlist-Elementen verknüpfen

Neben einer ID kann jedes Medienelement auch mit einem benutzerdefinierten Tag konfiguriert werden. Das kann jedes von der App bereitgestellte Objekt sein. Eine Verwendung von benutzerdefinierten Tags besteht darin, jedem Medienelement Metadaten hinzuzufügen:

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();

Erkennen, wenn die Wiedergabe zu einem anderen Medienelement wechselt

Wenn die Wiedergabe zu einem anderen Medienelement wechselt oder dasselbe Medienelement wiederholt wird, wird Listener.onMediaItemTransition(MediaItem, @MediaItemTransitionReason) aufgerufen. Dieser Callback empfängt das neue Medienelement zusammen mit einem @MediaItemTransitionReason, das angibt, warum der Übergang aufgetreten ist. Ein häufiger Anwendungsfall für onMediaItemTransition ist das Aktualisieren der Benutzeroberfläche der App für das neue Medienelement:

Kotlin

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

Java

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

Wenn die zum Aktualisieren der Benutzeroberfläche erforderlichen Metadaten mithilfe benutzerdefinierter Tags an jedes Medienelement angehängt werden, könnte eine Implementierung so aussehen:

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);
}

Erkennen, wenn sich die Playlist ändert

Wenn ein Medienelement hinzugefügt, entfernt oder verschoben wird, wird Listener.onTimelineChanged(Timeline, @TimelineChangeReason) sofort mit TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED aufgerufen. Dieser Callback wird auch dann aufgerufen, wenn der Player noch nicht vorbereitet wurde.

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);
  }
}

Wenn Informationen wie die Dauer eines Medienelements in der Playlist verfügbar sind, wird Timeline aktualisiert und onTimelineChanged mit TIMELINE_CHANGE_REASON_SOURCE_UPDATE aufgerufen. Weitere Gründe, die zu einer Aktualisierung der Zeitachse führen können, sind:

  • Ein Manifest, das nach der Vorbereitung eines adaptiven Medienelements verfügbar wird.
  • Ein Manifest, das während der Wiedergabe eines Livestreams regelmäßig aktualisiert wird.