Interfejs API playlisty jest zdefiniowany przez interfejs Player
, który jest implementowany przez wszystkie implementacje ExoPlayer
. Playlisty umożliwiają odtwarzanie sekwencyjne wielu elementów multimedialnych. W tym przykładzie pokazujemy, 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ście między elementami playlisty jest płynne. Nie ma wymogu, aby filmy miały ten sam format (np. playlista może zawierać zarówno filmy H264, jak i VP9). Mogą być nawet różnych typów (czyli playlista może zawierać filmy, obrazy i strumienie audio). Na playliście możesz użyć tego samego MediaItem
kilka razy.
Modyfikowanie playlisty
Możesz dynamicznie modyfikować playlistę, dodając, przenosząc, usuwając lub zastępując elementy multimedialne. Możesz to zrobić zarówno przed odtworzeniem, jak i w jego trakcie, wywołując odpowiednie metody interfejsu API playlist:
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 są 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();
Podczas odtwarzania odtwarzacz automatycznie wprowadza zmiany w prawidłowy sposób:
- Jeśli aktualnie odtwarzany
MediaItem
zostanie przeniesiony, odtwarzanie nie zostanie przerwane, a po zakończeniu odtwarzania zostanie odtworzony nowy kanał. - Jeśli aktualnie odtwarzany film
MediaItem
zostanie usunięty, odtwarzacz automatycznie odtworzy pierwszy pozostały następcę lub przejdzie do stanu zakończenia, jeśli nie istnieje taki następca. - Jeśli obecnie odtwarzany
MediaItem
zostanie zastąpiony, odtwarzanie nie zostanie przerwane, o ile żadna z właściwości wMediaItem
istotnych dla odtwarzania nie ulegnie zmianie. Na przykład w większości przypadków można zaktualizować polaMediaItem.MediaMetadata
bez wpływu na odtwarzanie.
Wysyłanie zapytania dotyczącego playlisty
Zapytania dotyczące playlisty można wysyłać za pomocą parametrów Player.getMediaItemCount
i Player.getMediaItemAt
. Zapytania dotyczące aktualnie odtwarzanego elementu multimedialnego można wysłać, wywołując funkcję Player.getCurrentMediaItem
. Istnieją też inne wygodne metody, takie jak Player.hasNextMediaItem
lub Player.getNextMediaItemIndex
, które ułatwiają nawigację po playliście.
Tryby powtarzania
Odtwarzacz obsługuje 3 tryby powtarzania, które można ustawić w dowolnym momencie za pomocą Player.setRepeatMode
:
Player.REPEAT_MODE_OFF
: playlista nie jest powtarzana, a po odtworzeniu ostatniego elementu na playliście odtwarzacz przejdzie doPlayer.STATE_ENDED
.Player.REPEAT_MODE_ONE
: bieżący element jest powtarzany w nieskończonej pętli. Metody takie jakPlayer.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 niekończącej się pętli.
Tryb losowy
Tryb losowego można w każdej chwili włączyć lub wyłączyć za pomocą Player.setShuffleModeEnabled
. W trybie losowym odtwarzacz odtworzy playlistę w wylosowanej kolejności. Wszystkie elementy zostaną odtworzone raz, a tryb losowy można też połączyć z opcją Player.REPEAT_MODE_ALL
, aby powtarzać te same elementy w losowej kolejności w nieskończonym pętli. Po wyłączeniu trybu losowego odtwarzanie bieżącego elementu na playliście jest kontynuowane.
Pamiętaj, że indeksy zwracane przez metody takie jak Player.getCurrentMediaItemIndex
zawsze odnoszą się do pierwotnego, nieuporządkowanego porządku. Podobnie Player.seekToNextMediaItem
nie odtworzy elementu w miejscu player.getCurrentMediaItemIndex() + 1
, ale następnego elementu zgodnie z kolejnością losową. Wstawienie nowych elementów lub usunięcie elementów z playlisty pozwala zachować
wcześniejszą kolejność losową bez zmian.
Ustawianie niestandardowej kolejności losowania
Domyślnie odtwarzacz obsługuje losowanie za pomocą przycisku DefaultShuffleOrder
.
Możesz to dostosować, podając niestandardową implementację losowania 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żesz ustawić wartość 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 definiuje w prosty sposób identyfikatora multimediów dla elementu multimedialnego, używana jest reprezentacja ciągu znaków identyfikatora URI.
Powiązanie danych aplikacji z elementami playlisty
Oprócz identyfikatora do każdego elementu multimedialnego można też użyć tagu niestandardowego, którym może być dowolny obiekt dostarczony przez aplikację. Tagi niestandardowe można stosować m.in. do dołączania metadanych do poszczególnych multimediów:
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, kiedy odtwarzanie przechodzi do innego elementu multimedialnego;
Gdy odtwarzanie przechodzi do innego elementu multimedialnego lub rozpoczyna powtarzanie tego samego elementu multimedialnego, wywoływana jest funkcja Listener.onMediaItemTransition(MediaItem,
@MediaItemTransitionReason)
. Ten wywołanie zwrotne otrzymuje nowy element multimediów wraz z @MediaItemTransitionReason
, który wskazuje, dlaczego nastąpiła zmiana. Typowy przypadek użycia onMediaItemTransition
to 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 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, funkcja Listener.onTimelineChanged(Timeline, @TimelineChangeReason)
zostanie wywołana natychmiast z argumentem TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED
. Ta funkcja wywołania zwrotnego jest wywoływana 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 będą informacje na przykład o czasie trwania elementu multimedialnego na playliście, obiekt Timeline
zostanie zaktualizowany, a funkcja onTimelineChanged
zostanie wywołana za pomocą funkcji TIMELINE_CHANGE_REASON_SOURCE_UPDATE
. Inne powody, które mogą spowodować aktualizację osi czasu:
- Plik manifestu staje się dostępny po przygotowaniu adaptacyjnego elementu multimedialnego.
- Plik manifestu jest okresowo aktualizowany podczas odtwarzania transmisji na żywo.