재생목록 API는 모든 ExoPlayer
구현에서 구현하는 Player
인터페이스로 정의됩니다. 재생목록을 사용하면 여러 미디어 항목을 순차 재생할 수 있습니다. 다음 예는 동영상 2개가 포함된 재생목록의 재생을 시작하는 방법을 보여줍니다.
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()
자바
// 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))
자바
// 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()
자바
// 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
와 같은 다른 편의 메서드도 있습니다.
반복 모드
플레이어는 Player.setRepeatMode
를 사용하여 언제든지 설정할 수 있는 3가지 반복 모드를 지원합니다.
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
자바
// 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()
자바
// 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()
자바
// 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) }
자바
@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) }
자바
@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) } }
자바
@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
가 업데이트되고 onTimelineChanged
가 TIMELINE_CHANGE_REASON_SOURCE_UPDATE
를 사용하여 호출됩니다. 타임라인 업데이트의 다른 원인에는 다음이 포함됩니다.
- 적응형 미디어 항목을 준비한 후 매니페스트를 사용할 수 있게 됩니다.
- 라이브 스트림 재생 중에 주기적으로 업데이트되는 매니페스트입니다.