פלייליסטים

ה-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.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 כשיוצרים את item:

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. סיבות אחרות שעלולות לגרום עדכון ציר הזמן כולל:

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