播放清單 API 是由 Player
介面定義,而所有 ExoPlayer
實作項目都會實作此介面。播放清單可讓您依序播放多個媒體項目。以下範例說明如何開始播放含有兩部影片的播放清單:
// 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()
// 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();
播放清單中的項目之間可無縫轉換。不必是相同格式 (例如播放清單可以同時包含 H.264 和 VP9 影片)。它們也可能屬於不同的類型 (也就是說,播放清單中可以包含影片、圖片和純音訊串流)。您可在播放清單中多次使用相同的 MediaItem
。
修改播放清單
您可以新增、移動、移除或取代媒體項目,動態修改播放清單。無論是在播放前後,您都可以呼叫對應的播放清單 API 方法,完成這項操作:
// 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))
// 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));
系統也支援替換及清除整個播放清單:
// 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()
// 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
建構函式中設定自訂排序項目,藉此自訂排序順序:
// 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
// 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
:
// Build a media item with a media ID.
val mediaItem = MediaItem.Builder().setUri(uri).setMediaId(mediaId).build()
// Build a media item with a media ID.
MediaItem mediaItem = new MediaItem.Builder().setUri(uri).setMediaId(mediaId).build();
如果應用程式未明確定義媒體項目的媒體 ID,系統會使用 URI 的字串表示法。
將應用程式資料與播放清單項目建立關聯
除了 ID 以外,每個媒體項目也可設定自訂標記,此標記可以是任何應用程式提供的物件。自訂標記的其中一個用途,就是為每個媒體項目附加中繼資料:
// Build a media item with a custom tag.
val mediaItem = MediaItem.Builder().setUri(uri).setTag(metadata).build()
// Build a media item with a custom tag.
MediaItem mediaItem = new MediaItem.Builder().setUri(uri).setTag(metadata).build();
偵測播放內容移至其他媒體項目的時機
當播放內容轉換為其他媒體項目,或開始重複播放相同的媒體項目時,系統會呼叫 Listener.onMediaItemTransition(MediaItem,
@MediaItemTransitionReason)
。這個回呼會接收新的媒體項目,以及 @MediaItemTransitionReason
,指出發生轉換的原因。onMediaItemTransition
的常見用途是為新媒體項目更新應用程式的使用者介面:
override fun onMediaItemTransition(
mediaItem: MediaItem?,
@MediaItemTransitionReason reason: Int,
) {
updateUiForPlayingMediaItem(mediaItem)
}
@Override
public void onMediaItemTransition(
@Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {
updateUiForPlayingMediaItem(mediaItem);
}
如果使用自訂標記將更新 UI 所需的中繼資料附加至每個媒體項目,實作方式可能如下:
override fun onMediaItemTransition(
mediaItem: MediaItem?,
@MediaItemTransitionReason reason: Int,
) {
var metadata: CustomMetadata? = null
mediaItem?.localConfiguration?.let { localConfiguration ->
metadata = localConfiguration.tag as? CustomMetadata
}
updateUiForPlayingMediaItem(metadata)
}
@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);
}
偵測播放清單變更
新增、移除或移動媒體項目時,系統會立即呼叫 Listener.onTimelineChanged(Timeline, @TimelineChangeReason)
並使用 TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED
。即使玩家尚未做好準備,系統仍會呼叫此回呼。
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)
}
}
@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
。其他可能導致時間表更新的原因包括:
- 準備自動調整媒體項目後可供使用的資訊清單。
- 在直播播放期間定期更新的資訊清單。