Playlists

Die Playlist API wird von der Player-Schnittstelle definiert, die durch alle ExoPlayer-Implementierungen implementiert wird. Playlists ermöglichen die sequentielle Wiedergabe mehrerer Medienelemente. Das folgende Beispiel zeigt, 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 ist nicht erforderlich, dass sie dasselbe Format haben. Zum Beispiel kann eine Playlist sowohl H264- als auch VP9-Videos enthalten. Sie können sogar unterschiedliche Typen haben. Das heißt, eine Playlist kann sowohl Video- als auch reine Audiostreams enthalten. Du kannst dasselbe MediaItem-Element in einer Playlist mehrmals verwenden.

Playlist ändern

Du kannst eine Playlist dynamisch ändern, indem du Medienelemente hinzufügst, verschiebst, entfernst oder ersetzt. Dies kann sowohl vor als auch während der Wiedergabe durch Aufrufen der entsprechenden Playlist API-Methoden erfolgen:

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

Das Ersetzen und Löschen der gesamten Playlist wird ebenfalls unterstützt:

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

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

  • Wenn die aktuell wiedergegebene MediaItem verschoben wird, wird die Wiedergabe nicht unterbrochen und nach Abschluss wird der neue Nachfolger abgespielt.
  • Wenn die aktuell wiedergegebene MediaItem entfernt wird, spielt der Player automatisch den ersten verbleibenden Nachfolger wieder oder wechselt in den Status „Beendet“, wenn kein solcher Nachfolger vorhanden ist.
  • Wird die aktuell wiedergegebene MediaItem ersetzt, wird die Wiedergabe nicht unterbrochen, wenn sich keines der für die Wiedergabe relevanten Attribute im MediaItem ändert. Beispielsweise ist es in den meisten Fällen möglich, die MediaItem.MediaMetadata-Felder 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 eingestellt werden können:

  • Player.REPEAT_MODE_OFF: Die Playlist wird nicht wiederholt und der Player wechselt zu Player.STATE_ENDED, sobald das letzte Element der Playlist wiedergegeben wurde.
  • Player.REPEAT_MODE_ONE: Das aktuelle Element wird in einer Endlosschleife wiederholt. Methoden wie Player.seekToNextMediaItem ignorieren dies und suchen 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 Zufallsmix 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. 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 von Methoden wie Player.getCurrentMediaItemIndex zurückgegebenen Indexe beziehen sich immer auf die ursprüngliche, nicht nach dem Zufallsprinzip angeordnete Reihenfolge. Ebenso gibt Player.seekToNextMediaItem das Element nicht bei player.getCurrentMediaItemIndex() + 1 wieder, sondern das nächste Element gemäß der Shuffle-Reihenfolge. Wenn du neue Elemente in die Playlist einfügst oder Elemente entfernst, bleibt die vorhandene Zufallsreihenfolge so weit wie möglich unverändert.

Benutzerdefinierte Shuffle-Reihenfolge festlegen

Standardmäßig unterstützt der Player die Zufallswiedergabe mithilfe von DefaultShuffleOrder. Dies kann angepasst werden, indem eine benutzerdefinierte Implementierung der Shuffle-Reihenfolge angegeben oder eine benutzerdefinierte Reihenfolge im DefaultShuffleOrder-Konstruktor 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

Zur Identifizierung von Playlist-Elementen kann beim Erstellen des Elements MediaItem.mediaId 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 in einer App keine Medien-ID für ein Medienelement explizit definiert wird, wird die Stringdarstellung des URI verwendet.

App-Daten mit Playlist-Elementen verknüpfen

Zusätzlich zu einer ID kann jedes Medienelement auch mit einem benutzerdefinierten Tag konfiguriert werden, bei dem es sich um ein beliebiges von der App bereitgestelltes Objekt handeln kann. Mit benutzerdefinierten Tags können Sie z. B. Metadaten an jedes Medienelement anhängen:

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 bei der Wiedergabe zu einem anderen Medienelement gewechselt wird

Wenn die Wiedergabe zu einem anderen Medienelement überspringt oder wiederholt dasselbe Medienelement wiederholt, wird Listener.onMediaItemTransition(MediaItem, @MediaItemTransitionReason) aufgerufen. Dieser Callback empfängt das neue Medienelement zusammen mit einem @MediaItemTransitionReason, der angibt, warum der Übergang stattgefunden hat. Ein häufiger Anwendungsfall für onMediaItemTransition ist die Aktualisierung der App-UI 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 UI erforderlichen Metadaten mithilfe von benutzerdefinierten 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);
}

Änderungen der Playlist erkennen

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 für eine Aktualisierung des Zeitplans sind:

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