播放列表

播放列表 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.getMediaItemCountPlayer.getMediaItemAt。可以查询当前正在播放的媒体项 调用 Player.getCurrentMediaItem。还有一些其他便利 Player.hasNextMediaItemPlayer.getNextMediaItemIndex 等方法 简化在播放列表中的导航。

重复模式

播放器支持 3 种重复模式,你可以随时使用 Player.setRepeatMode

  • Player.REPEAT_MODE_OFF:播放列表不会重复播放,播放器将 播放列表中的最后一项结束后,YouTube 将转到 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 的一个常见用例是更新 新媒体项的应用界面:

Kotlin

override fun onMediaItemTransition(
  mediaItem: MediaItem?,
  @MediaItemTransitionReason reason: Int,
) {
  updateUiForPlayingMediaItem(mediaItem)
}

Java

@Override
public void onMediaItemTransition(
    @Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {
  updateUiForPlayingMediaItem(mediaItem);
}

如果使用 那么实现代码可能如下所示:

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);
}

检测播放列表何时发生更改

添加、移除或移动媒体内容时, 调用 Listener.onTimelineChanged(Timeline, @TimelineChangeReason) 立即与 TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED 对话。此回调是 调用该方法。

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 并调用 onTimelineChangedTIMELINE_CHANGE_REASON_SOURCE_UPDATE共享。导致 时间表更新包括:

  • 准备好自适应媒体项后,清单变为可用状态。
  • 在直播播放期间定期更新的清单。