פלייליסטים

ה-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 כמה פעמים בפלייליסט.

שינוי הפלייליסט

אתם יכולים לשנות פלייליסט באופן דינמי על ידי הוספה, העברה, הסרה או החלפה של פריטי מדיה. אפשר לעשות זאת גם לפני ההפעלה וגם במהלכה, על ידי קריאה ל-methods המתאימים של 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. אפשר להתאים אישית את האפשרות הזו על ידי הוספת הטמעה מותאמת אישית של סדר הערבוב, או על ידי הגדרת סדר מותאם אישית ב-constructor של 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). הקריאה החוזרת (callback) הזו מקבלת את פריט המדיה החדש, יחד עם @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. הקריאה הזו לפעולה חוזרת (callback) גם אם הנגן עדיין לא מוכן.

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. סיבות נוספות לעדכון ציר הזמן:

  • מניפסט שזמין אחרי הכנת פריט מדיה אדפטיבי.
  • מניפסט שמתעדכן מדי פעם במהלך ההפעלה של שידור חי.