ממשק Player מגדיר את Playlist API, וכל ההטמעות של 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 כמה פעמים בפלייליסט.
שינוי הפלייליסט
אתם יכולים לשנות פלייליסט באופן דינמי על ידי הוספה, העברה, הסרה או החלפה של פריטי מדיה. אפשר לעשות את זה לפני ההפעלה או במהלך ההפעלה באמצעות קריאה לשיטות המתאימות של Playlist 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();
אם אפליקציה לא מגדירה באופן מפורש מזהה מדיה לפריט מדיה, נעשה שימוש בייצוג המחרוזת של ה-URI.
שיוך נתוני אפליקציה לפריטים בפלייליסט
בנוסף למזהה, אפשר להגדיר לכל פריט מדיה גם תג מותאם אישית, שיכול להיות כל אובייקט שסופק על ידי האפליקציה. אחד השימושים בתגים מותאמים אישית הוא צירוף מטא-נתונים לכל פריט מדיה:
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 מתעדכנת והפונקציה onTimelineChanged מופעלת עם TIMELINE_CHANGE_REASON_SOURCE_UPDATE. סיבות אחרות שיכולות לגרום לעדכון ציר הזמן:
- קובץ מניפסט הופך לזמין אחרי שמכינים פריט מדיה דינמי.
- קובץ מניפסט שמתעדכן מעת לעת במהלך הפעלת שידור חי.