Danh sách phát

API danh sách phát được xác định bởi giao diện Player, được triển khai bằng tất cả các phương thức triển khai ExoPlayer. Danh sách phát cho phép phát tuần tự nhiều mục nội dung nghe nhìn. Ví dụ sau đây cho thấy cách bắt đầu phát một danh sách phát chứa hai video:

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

Quá trình chuyển đổi giữa các mục trong danh sách phát diễn ra liền mạch. Không bắt buộc các video phải có cùng định dạng (ví dụ: danh sách phát có thể chứa cả video H264 và VP9). Các nội dung này thậm chí có thể thuộc nhiều loại (tức là một danh sách phát có thể chứa video, hình ảnh và luồng chỉ âm thanh). Bạn có thể sử dụng cùng một MediaItem nhiều lần trong một danh sách phát.

Sửa đổi danh sách phát

Bạn có thể linh động sửa đổi danh sách phát bằng cách thêm, di chuyển, xoá hoặc thay thế các mục nội dung nghe nhìn. Bạn có thể thực hiện việc này cả trước và trong khi phát bằng cách gọi các phương thức API danh sách phát tương ứng:

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

Bạn cũng có thể thay thế và xoá toàn bộ danh sách phát:

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

Trình phát sẽ tự động xử lý các nội dung sửa đổi trong quá trình phát theo cách chính xác:

  • Nếu MediaItem đang phát bị di chuyển, quá trình phát sẽ không bị gián đoạn và phiên bản kế tiếp mới sẽ được phát sau khi hoàn tất.
  • Nếu MediaItem đang phát bị xoá, người chơi sẽ tự động phát phiên bản kế tiếp đầu tiên còn lại hoặc chuyển sang trạng thái đã kết thúc nếu không có phiên bản kế thừa nào như vậy.
  • Nếu MediaItem đang phát được thay thế, thì quá trình phát sẽ không bị gián đoạn nếu không có thuộc tính nào trong MediaItem liên quan đến việc phát thay đổi. Ví dụ: bạn có thể cập nhật các trường MediaItem.MediaMetadata trong hầu hết các trường hợp mà không ảnh hưởng đến việc phát.

Truy vấn danh sách phát

Bạn có thể truy vấn danh sách phát bằng Player.getMediaItemCountPlayer.getMediaItemAt. Bạn có thể truy vấn mục nội dung đa phương tiện đang phát bằng cách gọi Player.getCurrentMediaItem. Ngoài ra, còn có các phương thức thuận tiện khác như Player.hasNextMediaItem hoặc Player.getNextMediaItemIndex để đơn giản hoá việc điều hướng trong danh sách phát.

Chế độ lặp lại

Người chơi hỗ trợ 3 chế độ lặp lại mà bạn có thể đặt bất cứ lúc nào bằng Player.setRepeatMode:

  • Player.REPEAT_MODE_OFF: Danh sách phát không được lặp lại và trình phát sẽ chuyển sang Player.STATE_ENDED sau khi phát xong mục cuối cùng trong danh sách phát.
  • Player.REPEAT_MODE_ONE: Mục hiện tại được lặp lại trong một vòng lặp vô hạn. Các phương thức như Player.seekToNextMediaItem sẽ bỏ qua điều này và tìm đến mục tiếp theo trong danh sách, sau đó lặp lại trong một vòng lặp vô hạn.
  • Player.REPEAT_MODE_ALL: Toàn bộ danh sách phát lặp lại trong một vòng lặp vô tận.

Chế độ ngẫu nhiên

Bạn có thể bật hoặc tắt chế độ ngẫu nhiên bất cứ lúc nào bằng Player.setShuffleModeEnabled. Khi ở chế độ phát ngẫu nhiên, trình phát sẽ phát danh sách phát theo thứ tự được tính toán trước, ngẫu nhiên. Tất cả các mục sẽ được phát một lần và bạn cũng có thể kết hợp chế độ phát ngẫu nhiên với Player.REPEAT_MODE_ALL để lặp lại cùng một thứ tự ngẫu nhiên trong một vòng lặp vô tận. Khi chế độ phát ngẫu nhiên bị tắt, quá trình phát sẽ tiếp tục từ mục hiện tại ở vị trí ban đầu trong danh sách phát.

Xin lưu ý rằng các chỉ mục do các phương thức như Player.getCurrentMediaItemIndex trả về luôn tham chiếu đến thứ tự ban đầu, chưa được xáo trộn. Tương tự, Player.seekToNextMediaItem sẽ không phát mục tại player.getCurrentMediaItemIndex() + 1 mà là mục tiếp theo theo thứ tự xáo trộn. Việc thêm các mục mới vào danh sách phát hoặc xoá các mục sẽ giúp giữ nguyên thứ tự xáo trộn hiện có nhiều nhất có thể.

Đặt thứ tự trộn bài tuỳ chỉnh

Theo mặc định, trình phát hỗ trợ phát ngẫu nhiên bằng cách sử dụng DefaultShuffleOrder. Bạn có thể tuỳ chỉnh điều này bằng cách triển khai thứ tự xáo trộn tuỳ chỉnh hoặc bằng cách đặt thứ tự tuỳ chỉnh trong hàm khởi tạo 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);

Xác định các mục trong danh sách phát

Để xác định các mục trong danh sách phát, bạn có thể đặt MediaItem.mediaId khi tạo mục:

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

Nếu một ứng dụng không xác định rõ mã nội dung nghe nhìn cho một mục nội dung nghe nhìn, thì hệ thống sẽ sử dụng cách trình bày chuỗi của URI.

Liên kết dữ liệu ứng dụng với các mục trong danh sách phát

Ngoài mã nhận dạng, mỗi mục nội dung đa phương tiện cũng có thể được định cấu hình bằng một thẻ tuỳ chỉnh. Thẻ này có thể là bất kỳ đối tượng nào do ứng dụng cung cấp. Một cách sử dụng thẻ tuỳ chỉnh là đính kèm siêu dữ liệu vào từng mục nội dung nghe nhìn:

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

Phát hiện thời điểm quá trình phát chuyển sang một mục nội dung đa phương tiện khác

Khi quá trình phát chuyển sang một mục nội dung nghe nhìn khác hoặc bắt đầu lặp lại cùng một mục nội dung nghe nhìn, Listener.onMediaItemTransition(MediaItem, @MediaItemTransitionReason) sẽ được gọi. Lệnh gọi lại này sẽ nhận được mục nội dung nghe nhìn mới, cùng với @MediaItemTransitionReason cho biết lý do chuyển đổi đã xảy ra. Một trường hợp sử dụng phổ biến cho onMediaItemTransition là cập nhật giao diện người dùng của ứng dụng cho mục nội dung đa phương tiện mới:

Kotlin

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

Java

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

Nếu siêu dữ liệu cần thiết để cập nhật giao diện người dùng được đính kèm vào từng mục nội dung đa phương tiện bằng thẻ tuỳ chỉnh, thì quá trình triển khai có thể có dạng như sau:

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

Phát hiện thời điểm danh sách phát thay đổi

Khi một mục nội dung nghe nhìn được thêm, xoá hoặc di chuyển, Listener.onTimelineChanged(Timeline, @TimelineChangeReason) sẽ được gọi ngay lập tức bằng TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED. Lệnh gọi lại này được gọi ngay cả khi người chơi chưa được chuẩn bị.

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

Khi có thông tin như thời lượng của một mục nội dung đa phương tiện trong danh sách phát, Timeline sẽ được cập nhật và onTimelineChanged sẽ được gọi bằng TIMELINE_CHANGE_REASON_SOURCE_UPDATE. Các lý do khác có thể dẫn đến việc cập nhật dòng thời gian bao gồm:

  • Tệp kê khai sẽ có sẵn sau khi chuẩn bị một mục nội dung nghe nhìn thích ứng.
  • Tệp kê khai được cập nhật định kỳ trong khi phát sự kiện phát trực tiếp.