w playlistach.

Interfejs API playlisty jest zdefiniowany przez interfejs Player, który jest implementowany przez wszystkie implementacje ExoPlayer. Playlisty umożliwiają sekwencyjne odtwarzanie wielu elementów multimedialnych. Poniższy przykład pokazuje, 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 na playliście są płynne. Nie ma wymogu, aby były one w tym samym formacie (np. na playliście mogą znajdować się filmy w formatach H264 i VP9). Mogą one nawet być różnych typów (czyli lista odtwarzania może zawierać filmy, obrazy i strumienie tylko audio). Możesz użyć tego samego MediaItem wiele razy na jednej playliście.

Modyfikowanie playlisty

Możesz dynamicznie modyfikować playlistę, dodając, przenosząc, usuwając lub zastępując elementy multimedialne. Możesz to zrobić przed odtwarzaniem i w jego trakcie, 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));

Obsługiwane jest też zastępowanie i czyszczenie całej playlisty:

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 obsługuje modyfikacje podczas odtwarzania w odpowiedni sposób:

  • Jeśli aktualnie odtwarzany MediaItem zostanie przeniesiony, odtwarzanie nie zostanie przerwane, a po jego zakończeniu zostanie odtworzony nowy następca.
  • Jeśli aktualnie odtwarzany element MediaItem zostanie usunięty, odtwarzacz automatycznie odtworzy pierwszy pozostały element następny lub przejdzie do stanu zakończonego, jeśli nie ma takiego elementu.
  • Jeśli aktualnie odtwarzany element MediaItem zostanie zastąpiony, odtwarzanie nie zostanie przerwane, o ile żadna z właściwości w elemencie MediaItem istotna dla odtwarzania nie ulegnie zmianie. Na przykład w większości przypadków można zaktualizować MediaItem.MediaMetadatapola bez wpływu na odtwarzanie.

Wysyłanie zapytań dotyczących playlisty

O playlistę można wysłać zapytanie za pomocą parametrów Player.getMediaItemCountPlayer.getMediaItemAt. Obecnie odtwarzany element multimedialny można sprawdzić, wywołując funkcję Player.getCurrentMediaItem. Dostępne są też inne wygodne metody, takie jak Player.hasNextMediaItem lub Player.getNextMediaItemIndex, które ułatwiają poruszanie się po playliście.

Tryby powtarzania

Odtwarzacz obsługuje 3 tryby powtarzania, które można ustawić w dowolnym momencie za pomocą przyciskuPlayer.setRepeatMode:

  • Player.REPEAT_MODE_OFF: playlista nie jest powtarzana, a odtwarzacz przejdzie do stanu Player.STATE_ENDED po odtworzeniu ostatniego elementu na playliście.
  • Player.REPEAT_MODE_ONE: bieżący element jest powtarzany w nieskończonej pętli. Metody takie jak Player.seekToNextMediaItem zignorują to i przejdą do następnego elementu na liście, który będzie powtarzany w nieskończonej pętli.
  • Player.REPEAT_MODE_ALL: cała playlista jest powtarzana w nieskończonej pętli.

Tryb odtwarzania losowego

Tryb odtwarzania losowego można włączyć lub wyłączyć w dowolnym momencie za pomocą ikony Player.setShuffleModeEnabled. W trybie losowym odtwarzacz będzie odtwarzać playlistę w losowej kolejności. Wszystkie elementy zostaną odtworzone raz. Tryb losowy można też połączyć z Player.REPEAT_MODE_ALL, aby powtarzać tę samą losową kolejność w nieskończonej pętli. Gdy tryb losowego odtwarzania jest wyłączony, odtwarzanie jest kontynuowane od bieżącego elementu w jego pierwotnym miejscu na playliście.

Pamiętaj, że indeksy zwracane przez metody takie jak Player.getCurrentMediaItemIndex zawsze odnoszą się do oryginalnej, nieprzemieszanej kolejności. Podobnie Player.seekToNextMediaItem nie odtworzy elementu w pozycji player.getCurrentMediaItemIndex() + 1, ale następny element zgodnie z kolejnością odtwarzania losowego. Wstawianie nowych elementów do playlisty lub usuwanie z niej elementów w miarę możliwości nie zmienia dotychczasowej kolejności losowej.

Ustawianie niestandardowej kolejności losowej

Domyślnie odtwarzacz obsługuje losowe odtwarzanie za pomocą ikony DefaultShuffleOrder. Możesz to dostosować, podając niestandardową implementację kolejności losowej 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ć parametr 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 zdefiniuje jawnie identyfikatora multimediów dla elementu multimedialnego, użyty zostanie ciąg znaków reprezentujący URI.

Powiązywanie danych aplikacji z elementami playlisty

Oprócz identyfikatora każdy element multimedialny można też skonfigurować za pomocą niestandardowego tagu, który może być dowolnym obiektem dostarczonym przez aplikację. Jednym z zastosowań tagów niestandardowych jest 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 odtwarzania do innego elementu multimedialnego

Gdy odtwarzanie przechodzi do innego elementu multimedialnego lub zaczyna powtarzać ten sam element, wywoływana jest funkcja Listener.onMediaItemTransition(MediaItem, @MediaItemTransitionReason). Funkcja zwrotna otrzymuje nowy element multimedialny wraz z wartością @MediaItemTransitionReason wskazującą przyczynę przejścia. Częstym przypadkiem użycia onMediaItemTransition jest aktualizowanie 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 zaktualizowania 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

Gdy element multimedialny zostanie dodany, usunięty lub przeniesiony, wywoływana jest funkcja Listener.onTimelineChanged(Timeline, @TimelineChangeReason) z parametrem TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED. To wywołanie zwrotne jest 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 dostępne staną się informacje takie jak czas trwania elementu multimedialnego na playliście, Timeline zostanie zaktualizowany, a onTimelineChanged zostanie wywołany z parametrem TIMELINE_CHANGE_REASON_SOURCE_UPDATE. Inne przyczyny aktualizacji osi czasu:

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