w playlistach.

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 w MediaItem istotnych dla odtwarzania nie ulegnie zmianie. Na przykład w większości przypadków można zaktualizować pola MediaItem.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 do Player.STATE_ENDED.
  • 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 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.