播放清單 API 是由 Player
介面定義,由所有 ExoPlayer
實作都實作。播放清單可讓多個媒體項目依序播放。以下範例說明如何開始播放含有兩部影片的播放清單:
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();
播放清單中的項目之間可以流暢切換,不一定要格式相同 (例如,播放清單可以同時包含 H264 和 VP9 影片)。它們甚至可能不同類型 (也就是說,播放清單可以同時包含影片和音訊串流)。您可以在播放清單中多次使用同一個 MediaItem
。
修改播放清單
您可以透過新增、移動、移除或取代媒體項目,動態修改播放清單。您可以在播放前和播放期間呼叫對應的播放清單 API 方法,藉此完成這項操作:
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));
系統也支援取代和清除整個播放清單:
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();
播放器以正確方式自動處理播放期間的修改作業:
- 如果移動目前正在播放的
MediaItem
,播放作業不會中斷,且會在完成時播放新的後續版本。 - 如果移除目前播放的
MediaItem
,播放器會自動播放剩餘的第一個後續狀態;如果沒有後續的後續狀態,播放器則會進入已結束狀態。 - 如果取代目前播放的
MediaItem
,只要MediaItem
中沒有任何與播放作業相關的屬性,則播放作業不會中斷。舉例來說,在大多數情況下,您可以在不影響播放的情況下更新MediaItem.MediaMetadata
欄位。
查詢播放清單
您可以使用 Player.getMediaItemCount
和 Player.getMediaItemAt
查詢播放清單。呼叫 Player.getCurrentMediaItem
即可查詢目前正在播放的媒體項目。還有其他便利的方法,例如 Player.hasNextMediaItem
或 Player.getNextMediaItemIndex
,可簡化播放清單中的導覽情形。
重複模式
玩家支援 3 種重複模式,隨時可使用 Player.setRepeatMode
設定:
Player.REPEAT_MODE_OFF
:播放清單不會重複,且只要播放清單中的最後一個項目播放完畢,播放器就會轉換為Player.STATE_ENDED
。Player.REPEAT_MODE_ONE
:目前項目會在無限迴圈中重複出現。Player.seekToNextMediaItem
等方法會忽略此方法,並跳轉至清單中的下一個項目,之後會在無盡迴圈中重複出現。Player.REPEAT_MODE_ALL
:整個播放清單會不斷重複出現。
隨機播放模式
您隨時可以使用 Player.setShuffleModeEnabled
啟用或停用重組模式。在隨機播放模式下,播放器會以預先運算的隨機順序播放播放清單。所有項目都會播放一次,而重組模式也可以與 Player.REPEAT_MODE_ALL
結合,以不斷重複進行相同的隨機順序。隨機播放模式關閉後,播放功能會從目前項目在播放清單中的原始位置繼續播放。
請注意,由 Player.getCurrentMediaItemIndex
等方法傳回的索引一律是指原始的未重組順序。同樣地,Player.seekToNextMediaItem
不會在 player.getCurrentMediaItemIndex() + 1
播放該項目,但會根據重組順序播放下一個項目。在播放清單中插入新項目或移除項目,會盡可能讓現有的隨機排列順序保持不變。
設定自訂重組順序
根據預設,播放器支援使用 DefaultShuffleOrder
隨機排序。如要自訂順序,您可以提供自訂重組順序實作,或在 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);
識別播放清單項目
如要識別播放清單項目,可以在建構項目時設定 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();
如果應用程式未明確定義媒體項目的媒體 ID,則會使用以 URI 表示的字串。
將應用程式資料與播放清單項目建立關聯
除了 ID 以外,每個媒體項目都可透過自訂標記設定,可以是任何應用程式提供的物件。自訂標記的其中一種用途,就是將中繼資料附加到每個媒體項目:
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();
在播放作業轉換至其他媒體項目時偵測
當播放轉換到其他媒體項目,或開始重複播放同一個媒體項目時,系統會呼叫 Listener.onMediaItemTransition(MediaItem,
@MediaItemTransitionReason)
。這個回呼會收到新媒體項目,以及指出轉場效果的 @MediaItemTransitionReason
。onMediaItemTransition
的常見用途是更新新媒體項目的應用程式 UI:
Kotlin
override fun onMediaItemTransition( mediaItem: MediaItem?, @MediaItemTransitionReason reason: Int, ) { updateUiForPlayingMediaItem(mediaItem) }
Java
@Override public void onMediaItemTransition( @Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) { updateUiForPlayingMediaItem(mediaItem); }
如果更新 UI 所需的中繼資料是透過自訂標記附加至每個媒體項目,實作方式可能會像這樣:
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); }
偵測播放清單變更的時間
新增、移除或移動媒體項目時,系統會立即使用 TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED
呼叫 Listener.onTimelineChanged(Timeline, @TimelineChangeReason)
。即使玩家尚未準備,系統仍會呼叫此回呼。
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); } }
當播放清單中某個媒體項目的時間長度等資訊時,系統就會更新 Timeline
,並使用 TIMELINE_CHANGE_REASON_SOURCE_UPDATE
呼叫 onTimelineChanged
。導致時間軸更新的其他原因包括:
- 資訊清單在準備自動調整媒體項目之後可供使用。
- 資訊清單會在直播播放期間定期更新。