w playlistach.

Interfejs API playlisty jest definiowany przez interfejs Player, który jest zaimplementowany przez wszystkie implementacje ExoPlayer. Playlisty umożliwiają sekwencyjne odtwarzanie wielu elementów multimedialnych. Z przykładu poniżej dowiesz się, jak rozpocząć odtwarzanie playlisty zawierającej 2 filmy:

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

Przejścia między elementami playlisty są płynne. Nie ma wymogu, by były w tym samym formacie (na przykład playlista może zawierać zarówno filmy H264, jak i VP9). Mogą one być różne (tzn. playlista może zawierać zarówno strumienie wideo, jak i audio). Tego samego elementu MediaItem możesz użyć kilka razy w ramach playlisty.

Modyfikowanie playlisty

Możesz dynamicznie modyfikować playlistę przez dodawanie, przenoszenie, usuwanie lub zastępowanie elementów multimedialnych. Można to zrobić zarówno przed odtwarzaniem, jak i w trakcie odtwarzania, wywołując odpowiednie metody interfejsu API playlisty:

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

Możesz też zastępować i usuwać całą 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();

Odtwarzacz automatycznie wprowadza zmiany podczas odtwarzania:

  • Jeśli aktualnie odtwarzany utwór MediaItem zostanie przeniesiony, odtwarzanie nie zostanie przerwane i po zakończeniu zostanie odtworzony jego nowy następca.
  • Jeśli element MediaItem, który obecnie jest odtwarzany, zostanie usunięty, odtwarzacz automatycznie rozpocznie odtwarzanie pierwszej pozostałej części następcy, a jeśli nie ma następcy – przejdzie do stanu zakończenia odtwarzania.
  • Jeśli obecnie odtwarzany element MediaItem zostanie zastąpiony, odtwarzanie nie zostanie przerwane, jeśli żadna z właściwości MediaItem, które go dotyczą, nie ulegnie zmianie. W większości przypadków można na przykład zaktualizować pola MediaItem.MediaMetadata, nie wpływając na odtwarzanie.

Zapytanie dotyczące playlisty

Zapytanie o playlistę można wysłać za pomocą parametrów Player.getMediaItemCount i Player.getMediaItemAt. Można przesłać zapytanie o odtwarzany obecnie element multimedialny, wywołując metodę Player.getCurrentMediaItem. Istnieją też inne, wygodne metody, takie jak Player.hasNextMediaItem czy Player.getNextMediaItemIndex, które upraszczają nawigację po playliście.

Tryby powtarzania

Odtwarzacz obsługuje 3 tryby powtarzania, które można ustawić w każdej chwili w Player.setRepeatMode:

  • Player.REPEAT_MODE_OFF: playlista nie jest powtarzana i po odtworzeniu ostatniego elementu na playliście odtwarzacz zostanie przeniesiony do trybu Player.STATE_ENDED.
  • Player.REPEAT_MODE_ONE: bieżący element powtarza się w niekończącej się pętli. Metody takie jak Player.seekToNextMediaItem zignorują tę wiadomość i przeprowadzą do następnego elementu na liście, który będzie powtarzany w niekończącej się pętli.
  • Player.REPEAT_MODE_ALL: cała playlista powtarza się w niekończącej się pętli.

Tryb tasowania

Tryb tasowania możesz w każdej chwili włączyć lub wyłączyć w Player.setShuffleModeEnabled. W trybie losowym odtwarzacz odtwarza playlistę w wstępnie ustalonej, losowej kolejności. Wszystkie elementy zostaną odtworzone raz. Tryb tasowania można też połączyć z funkcją Player.REPEAT_MODE_ALL, aby w nieskończonej pętli powtarzać tę samą kolejność losową. Gdy tryb odtwarzania losowego jest wyłączony, odtwarzanie bieżącego elementu jest kontynuowane na jego pierwotnej pozycji na playliście.

Pamiętaj, że indeksy zwracane przez metody takie jak Player.getCurrentMediaItemIndex zawsze odwołują się do pierwotnej kolejności bez kolejności. Analogicznie Player.seekToNextMediaItem nie odtworzy elementu pod adresem player.getCurrentMediaItemIndex() + 1, ale jako następny zgodnie z kolejnością losową. Wstawianie nowych elementów do playlisty lub usuwanie elementów sprawi, że dotychczasowa kolejność odtwarzania nie ulegnie zmianie.

Ustawianie niestandardowej kolejności losowej

Domyślnie odtwarzacz obsługuje tasowanie za pomocą komponentu DefaultShuffleOrder. Można to dostosować, stosując implementację niestandardowej kolejności tasowania lub ustawiając niestandardową kolejność w konstruktorze 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);

Identyfikowanie elementów playlisty

Aby zidentyfikować elementy playlisty, podczas tworzenia elementu można ustawić MediaItem.mediaId:

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

Jeśli aplikacja nie określa wyraźnie identyfikatora multimediów dla elementu multimedialnego, używany jest ciąg reprezentujący identyfikator URI.

Powiązanie danych aplikacji z elementami playlist

Oprócz identyfikatora każdy element multimedialny można skonfigurować za pomocą tagu niestandardowego, który może być dowolnym obiektem dostarczanym przez aplikację. Niestandardowe tagi to na przykład dołączanie metadanych do każdego elementu multimedialnego:

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

Wykrywanie przejścia do innego elementu multimedialnego

Gdy odtwarzanie przechodzi do innego elementu multimedialnego lub rozpoczyna powtarzanie tego samego elementu, wywoływane jest polecenie Listener.onMediaItemTransition(MediaItem, @MediaItemTransitionReason). To wywołanie zwrotne odbiera nowy element multimedialny z identyfikatorem @MediaItemTransitionReason wskazującym powód przeniesienia. Typowym przypadkiem użycia onMediaItemTransition jest zaktualizowanie interfejsu aplikacji pod kątem nowego elementu multimedialnego:

Kotlin

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

Java

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

Jeśli metadane wymagane do aktualizacji interfejsu są dołączone do każdego elementu multimedialnego za pomocą tagów niestandardowych, implementacja może wyglądać tak:

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

Wykrywanie zmian na playliście

Po dodaniu, usunięciu lub przeniesieniu elementu multimedialnego Listener.onTimelineChanged(Timeline, @TimelineChangeReason) jest natychmiast wywoływany za pomocą funkcji TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED. Jest ono wywoływane nawet wtedy, gdy odtwarzacz nie został jeszcze przygotowany.

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

Gdy informacje takie jak czas trwania elementu multimedialnego na playliście staną się dostępne, parametr Timeline zostanie zaktualizowany, a pole onTimelineChanged zostanie wywoływane z wartością TIMELINE_CHANGE_REASON_SOURCE_UPDATE. Inne przyczyny aktualizacji osi czasu:

  • Plik manifestu pojawia się po przygotowaniu adaptacyjnego elementu multimedialnego.
  • Plik manifestu jest okresowo aktualizowany podczas odtwarzania transmisji na żywo.