האזנה לאירועי הפעלה
אירועים, כמו שינויים במצב ובשגיאות הפעלה, ידווחו כאירועים רשומים
Player.Listener
מופעים. כדי לרשום מאזינים לקבל
אירועים:
Kotlin
// Add a listener to receive events from the player. player.addListener(listener)
Java
// Add a listener to receive events from the player. player.addListener(listener);
בפונקציה Player.Listener
יש שיטות ברירת מחדל ריקות, לכן צריך רק להטמיע
אילו שיטות מעניינות אותך. תיאור מלא של Javadoc מופיע ב-Javadoc
את השיטות ואת מועד הקריאה שלהן. חלק מהשיטות החשובות ביותר
כמתואר בפירוט בהמשך.
המאזינים יכולים לבחור בין הטמעת קריאה חוזרת (callback) של אירוע בודד או
קריאה חוזרת (callback) גנרית של onEvents
, שמופעלת אחרי שאירוע אחד או יותר מתרחשים
את כל החלקים. בכתובת Individual callbacks vs onEvents
יש הסבר
צריכה להיות עדיפות לתרחישים שונים לדוגמה.
שינויים במצב ההפעלה
כדי לקבל שינויים במצב הנגן,
onPlaybackStateChanged(@State int state)
ברשומה
Player.Listener
. הנגן יכול להיות באחד מארבעה מצבי הפעלה:
Player.STATE_IDLE
: זהו המצב הראשוני, המצב שבו הנגן הופסק וכשההפעלה נכשלה. הנגן יאחסן משאבים מוגבלים בלבד במצב הזה.Player.STATE_BUFFERING
: הנגן לא יכול להפעיל מיד המיקום הנוכחי. הסיבה העיקרית לכך היא שצריך לטעון יותר נתונים.Player.STATE_READY
: השחקן יכול להפעיל מיד את הפריט הנוכחי המיקום.Player.STATE_ENDED
: הנגן סיים להפעיל את כל קובצי המדיה.
בנוסף למצבים האלה, לנגן יש דגל playWhenReady
לציון
שהמשתמש רוצה לשחק. כדי שהשינויים בסימון הזה יתקבלו על ידי הטמעה
onPlayWhenReadyChanged(playWhenReady, @PlayWhenReadyChangeReason int reason)
שחקן משחק (כלומר, המיקום שלו מתקדם) מוצג למשתמש) כאשר כל שלושת התנאים הבאים מתקיימים:
- השחקן נמצא במצב
Player.STATE_READY
playWhenReady
הואtrue
- ההפעלה לא מבוטלת בגלל סיבה שהוחזרה על ידי
Player.getPlaybackSuppressionReason
במקום לבדוק את הנכסים האלה בנפרד, Player.isPlaying
. כדי לקבל שינויים במצב הזה, צריך להטמיע
onIsPlayingChanged(boolean isPlaying)
:
Kotlin
player.addListener( object : Player.Listener { override fun onIsPlayingChanged(isPlaying: Boolean) { if (isPlaying) { // Active playback. } else { // Not playing because playback is paused, ended, suppressed, or the player // is buffering, stopped or failed. Check player.playWhenReady, // player.playbackState, player.playbackSuppressionReason and // player.playerError for details. } } } )
Java
player.addListener( new Player.Listener() { @Override public void onIsPlayingChanged(boolean isPlaying) { if (isPlaying) { // Active playback. } else { // Not playing because playback is paused, ended, suppressed, or the player // is buffering, stopped or failed. Check player.getPlayWhenReady, // player.getPlaybackState, player.getPlaybackSuppressionReason and // player.getPlaybackError for details. } } });
שגיאות הפעלה
אם מטמיעים את השגיאה, ייתכן שיתקבלו שגיאות שגורמות לכישלון של ההפעלה.
onPlayerError(PlaybackException error)
ברשומה
Player.Listener
. במקרה של כשל, השיטה הזו תיקרא
ממש לפני שמצב ההפעלה יעבור ל-Player.STATE_IDLE
.
ניתן לנסות שוב להפעיל סרטונים שנכשלו או הופסקו על ידי חיוג למספר ExoPlayer.prepare
.
לתשומת ליבכם: חלק מההטמעות של Player
מעבירים מופעים של מחלקות משנה של
PlaybackException
כדי לספק מידע נוסף על הכשל. עבור
לדוגמה, ExoPlayer
מעביר את ExoPlaybackException
, עם type
,
rendererIndex
, ושדות אחרים הספציפיים ל-ExoPlayer.
הדוגמה הבאה מראה איך לזהות מתי הפעלה נכשלה בגלל בעיה ברשת HTTP:
Kotlin
player.addListener( object : Player.Listener { override fun onPlayerError(error: PlaybackException) { val cause = error.cause if (cause is HttpDataSourceException) { // An HTTP error occurred. val httpError = cause // It's possible to find out more about the error both by casting and by querying // the cause. if (httpError is InvalidResponseCodeException) { // Cast to InvalidResponseCodeException and retrieve the response code, message // and headers. } else { // Try calling httpError.getCause() to retrieve the underlying cause, although // note that it may be null. } } } } )
Java
player.addListener( new Player.Listener() { @Override public void onPlayerError(PlaybackException error) { @Nullable Throwable cause = error.getCause(); if (cause instanceof HttpDataSourceException) { // An HTTP error occurred. HttpDataSourceException httpError = (HttpDataSourceException) cause; // It's possible to find out more about the error both by casting and by querying // the cause. if (httpError instanceof HttpDataSource.InvalidResponseCodeException) { // Cast to InvalidResponseCodeException and retrieve the response code, message // and headers. } else { // Try calling httpError.getCause() to retrieve the underlying cause, although // note that it may be null. } } } });
מעברים בין פלייליסטים
בכל פעם שהנגן משתנה לפריט מדיה חדש בפלייליסט
קוראים אל onMediaItemTransition(MediaItem mediaItem,
@MediaItemTransitionReason int reason)
אחרי שרושמים
Player.Listener
אובייקטים. הסיבה מציינת אם זו הייתה פעולה אוטומטית
מעבר, דילוג (לדוגמה אחרי קריאה ל-player.next()
), חזרה של
לאותו פריט, או שנגרמו כתוצאה משינוי בפלייליסט (לדוגמה, אם
פריט ההפעלה יוסר).
Metadata
מטא-נתונים שהוחזרו מ-player.getCurrentMediaMetadata()
יכולים להשתנות בגלל גורמים רבים
הסיבות: מעברים בין פלייליסטים, עדכוני מטא-נתונים של מודעות וידאו In-stream או עדכון
אמצע ההפעלה הנוכחית של MediaItem
.
אם ברצונך לבצע שינויים במטא-נתונים, למשל לעדכן ממשק משתמש שרואים בו
השם הנוכחי, אפשר להאזין לonMediaMetadataChanged
.
מחפש
קריאה לשיטות Player.seekTo
תוביל לסדרה של קריאה חוזרת (callback) למשתמשים שנרשמו
Player.Listener
מופעים:
onPositionDiscontinuity
עםreason=DISCONTINUITY_REASON_SEEK
. הדבר התוצאה הישירה של קריאה אלPlayer.seekTo
. הקריאה החוזרת היאPositionInfo
לשדות המיקום לפני ואחרי הדילוג.onPlaybackStateChanged
עם כל שינוי מיידי במצב שקשור לחיפוש. לתשומת ליבכם: יכול להיות שלא יהיה שינוי כזה.
קריאות חוזרות (callback) בודדות לעומת onEvents
המאזינים יכולים לבחור אם להטמיע קריאות חוזרות (callback) ספציפיות, כמו
onIsPlayingChanged(boolean isPlaying)
, והערך הכללי
התקשרות חזרה onEvents(Player player, Events events)
. הקריאה החוזרת הכללית מספקת
גישה לאובייקט Player
ומציין את הקבוצה של events
שהתרחשה
את כל החלקים. הקריאה החוזרת הזו תמיד מתבצעת אחרי הקריאות החוזרות שתואמות ל-
כל אירוע בנפרד.
Kotlin
override fun onEvents(player: Player, events: Player.Events) { if ( events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) || events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED) ) { uiModule.updateUi(player) } }
Java
@Override public void onEvents(Player player, Events events) { if (events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) || events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED)) { uiModule.updateUi(player); } }
צריך לתת עדיפות לאירועים ספציפיים במקרים הבאים:
- המאזינים מתעניינו בסיבות לשינויים. לדוגמה,
סופקו עבור
onPlayWhenReadyChanged
אוonMediaItemTransition
. - ה-listener פועל רק על הערכים החדשים שסופקו באמצעות פרמטרים של קריאה חוזרת או מפעיל משהו אחר שלא תלוי בפרמטרים של הקריאה החוזרת.
- בהטמעת ה-listener יש עדיפות ליצירת אינדיקציה ברורה וקריאה לגבי מה שמתרחש הפעיל את האירוע בשם ה-method.
- ה-listener מדווח למערכת ניתוח נתונים שאמורה לדעת את כל הפרטים אירועים נפרדים ושינויי מצב.
יש לתת עדיפות לonEvents(Player player, Events events)
הגנרית
במקרים הבאים:
- ה-listener רוצה להפעיל את אותה לוגיקה עבור מספר אירועים. עבור
לדוגמה, עדכון ממשק משתמש גם עבור
onPlaybackStateChanged
וגםonPlayWhenReadyChanged
. - ה-listener צריך גישה לאובייקט
Player
כדי להפעיל אירועים נוספים, לדוגמה דילוג אחרי מעבר של פריט מדיה. - ה-listener מתכוון להשתמש במספר ערכי מצב מדווחים
באמצעות קריאות חוזרות (callbacks) נפרדים, או בשילוב עם getter של
Player
שיטות. לדוגמה, שימוש ב-Player.getCurrentWindowIndex()
עם המאפייןTimeline
שסופק ב-onTimelineChanged
בטוח רק בתוךonEvents
קריאה חוזרת (callback). - המאזין מתעניין בשאלה אם האירועים התרחשו יחד באופן לוגי. עבור
לדוגמה,
onPlaybackStateChanged
עדSTATE_BUFFERING
בגלל פריט מדיה של המעבר לממשק החדש.
במקרים מסוימים, ייתכן שהמאזינים יצטרכו לשלב את הקריאות החוזרות הנפרדות עם
קריאה חוזרת (callback) כללית של onEvents
, לדוגמה, כדי להקליט סיבות לשינוי פריט מדיה
עם onMediaItemTransition
, אבל הפעולה תתבצע רק לאחר שאפשר יהיה להשתמש בכל השינויים במצב
יחד ב-onEvents
.
משתמש ב-AnalyticsListener
כשמשתמשים ב-ExoPlayer
, אפשר לרשום AnalyticsListener
בנגן
באמצעות התקשרות אל addAnalyticsListener
. AnalyticsListener
הטמעות יכולות
לקבל מידע על אירועים מפורטים שעשויים להיות שימושיים לניתוח נתונים ולרישום ביומן
למטרות. פרטים נוספים זמינים בדף ניתוח הנתונים.
משתמש ב-EventLogger
EventLogger
הוא AnalyticsListener
שמסופק ישירות על ידי הספרייה עבור
למטרות רישום ביומן. הוספת EventLogger
ל-ExoPlayer
כדי להפעיל את האפשרויות
רישום ביומן נוסף בשורה אחת:
Kotlin
player.addAnalyticsListener(EventLogger())
Java
player.addAnalyticsListener(new EventLogger());
פרטים נוספים זמינים בדף הרישום ביומן של ניפוי הבאגים.
הפעלת אירועי הפעלה במיקומי הפעלה מסוימים
תרחישים לדוגמה מסוימים מחייבים הפעלה של אירועי הפעלה במיקומי הפעלה מסוימים. הדבר
נתמך באמצעות PlayerMessage
. ניתן ליצור PlayerMessage
באמצעות
ExoPlayer.createMessage
. מיקום ההפעלה שבו יש להפעיל את הסרטון
ניתן להגדיר באמצעות PlayerMessage.setPosition
. ההודעות מבוצעות
שרשור ההפעלה כברירת מחדל, אבל ניתן להתאים אישית את האפשרות הזו
PlayerMessage.setLooper
אפשר להשתמש ב-PlayerMessage.setDeleteAfterDelivery
כדי לקבוע אם ההודעה תתבצע בכל פעם
המערכת נתקלה במצב הפעלה (ייתכן שמצב זה יתרחש מספר פעמים בגלל דילוג)
ומצבי חזרה), או רק בפעם הראשונה. אחרי שה-PlayerMessage
מוגדר, אפשר לתזמן אותו באמצעות PlayerMessage.send
.
Kotlin
player .createMessage { messageType: Int, payload: Any? -> } .setLooper(Looper.getMainLooper()) .setPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 120000) .setPayload(customPayloadData) .setDeleteAfterDelivery(false) .send()
Java
player .createMessage( (messageType, payload) -> { // Do something at the specified playback position. }) .setLooper(Looper.getMainLooper()) .setPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 120_000) .setPayload(customPayloadData) .setDeleteAfterDelivery(false) .send();