נגן הוא הרכיב באפליקציה שמאפשר הפעלה של פריטי מדיה.
ממשק Media3 Player
מגדיר סקירה כללית של הפונקציונליות שבדרך כלל מטופלת על ידי נגן. הנתונים האלה כוללים:
- השפעה על פקדי ההפעלה, כמו הפעלה, השהיה וסריקה
- שליחת שאילתות לגבי מאפיינים של המדיה שמופעלת כרגע, כמו מיקום ההפעלה
- ניהול פלייליסט או תור של פריטי מדיה
- הגדרת מאפייני ההפעלה, כמו ערבוב, חזרה, מהירות ועוצמת קול
- עיבוד וידאו למסך
Media3 מספק גם הטמעה של הממשק Player
, שנקראת ExoPlayer
.
ממשק משותף בין הרכיבים
כמה רכיבים ב-Media3 מיישמים את ממשק הנגן, לדוגמה:
רכיב | תיאור והערות לגבי התנהגות |
---|---|
ExoPlayer |
ממשק API לנגן מדיה והטמעת ברירת המחדל של הממשק Player . |
MediaController |
מתקשר עם MediaSession כדי לשלוח פקודות הפעלה. אם Player ו-MediaSession נמצאים ב-Service נפרד מ-Activity או מ-Fragment שבהם נמצא ממשק המשתמש של הנגן, אפשר להקצות את MediaController כנגן של ממשק המשתמש PlayerView . קריאות ל-method של הפעלה ולפלייליסטים נשלחות ל-Player דרך ה-MediaSession .
|
MediaBrowser |
בנוסף לפונקציונליות שמציע MediaController , הוא יוצר אינטראקציה עם MediaLibrarySession כדי לעיין בתוכן המדיה שזמין.
|
SimpleBasePlayer |
הטמעה של Player שמפחיתה את מספר השיטות שצריך להטמיע למינימום. שימושי כשמשתמשים בנגן מותאם אישית שרוצים לקשר ל-MediaSession .
|
ForwardingSimpleBasePlayer |
תת-סוג של SimpleBasePlayer שמיועד להעביר פעולות של הפעלה ל-Player אחר, תוך שמירה על אותן התאמות אישיות עקביות של התנהגות כמו ב-SimpleBasePlayer . אפשר להשתמש בכיתה הזו כדי לדכא או לשנות פעולות הפעלה ספציפיות.
|
CastPlayer |
הטמעה של Player שמתקשרת עם אפליקציית מקלט Cast. ההתנהגות תלויה בסשן Cast הבסיסי.
|
אמנם MediaSession
לא מטמיע את הממשק Player
, אבל נדרש Player
כשיוצרים אותו. המטרה שלו היא לספק גישה ל-Player
משרשראות או מתהליכים אחרים.
ארכיטקטורת ההפעלה של Media3
אם יש לכם גישה ל-Player
, עליכם להפעיל את השיטות שלו ישירות כדי להפעיל פקודות הפעלה. כדי לפרסם את ההפעלה ולתת למקורות חיצוניים שליטה בהפעלה, אפשר להטמיע MediaSession
. המקורות החיצוניים האלה מטמיעים MediaController
, שמאפשר להתחבר לסשן מדיה ולשלוח בקשות לפקודות הפעלה.
כשמפעילים מדיה ברקע, צריך לאכלס את סשן המדיה ואת הנגן ב-MediaSessionService
או ב-MediaLibraryService
שפועלים כשירות בחזית. כך תוכלו להפריד בין הנגן לבין הפעילות באפליקציה שמכילה את ממשק המשתמש לצורך בקרת ההפעלה. יכול להיות שתצטרכו להשתמש בנגן מדיה.
מצב הנגן
המצב של נגן מדיה שמטמיע את הממשק Player
מורכב בעיקר מ-4 קטגוריות של מידע:
- מצב ההפעלה
- אחזור באמצעות
getPlaybackState()
. - ערכי המצב שמוגדרים בממשק הם
STATE_IDLE
,STATE_BUFFERING
,STATE_READY
ו-STATE_ENDED
.
- אחזור באמצעות
- פלייליסט של פריטי מדיה
- רצף של
MediaItem
מופעים להפעלה. - אחזור באמצעות
getCurrentTimeline()
- מכונות
Player
יכולות לספק שיטות לפעולות בפלייליסט, כמו הוספה או הסרה שלMediaItem
, ושיטות נוחות כמוgetCurrentMediaItem()
.
- רצף של
- מאפייני הפעלה/השהיה, כמו:
playWhenReady
: אינדיקציה לכך שהמשתמש רוצה שהמדיה תופעל כשהדבר אפשרי או שתישאר מושהית- Playback suppression reason: אינדיקציה לסיבת ההשתקה של ההפעלה, אם רלוונטי, גם אם הערך של
playWhenReady
הואtrue
isPlaying
: אינדיקציה לכך שהנגן פועל כרגע. הערךtrue
יופיע רק אם סטטוס ההפעלה הואSTATE_READY
, הערך שלplayWhenReady
הואtrue
וההפעלה לא מושבתת.
- מיקום ההפעלה, כולל:
- Current media item index: המדד של
MediaItem
הנוכחי בפלייליסט. isPlayingAd
: אינדיקציה לכך שמודעה מוכנסת פועלת.- Current playback position: המיקום הנוכחי בהפעלה בתוך
MediaItem
הנוכחי או במודעה המוכנסת.
- Current media item index: המדד של
בנוסף, הממשק Player
מאפשר גישה לטראקים הזמינים, למטא-נתונים של המדיה, למהירות ההפעלה, לנפח ולמאפיינים משניים אחרים של ההפעלה.
האזנה לשינויים
משתמשים ב-Player.Listener
כדי להאזין לשינויים ב-Player
. במאמר אירועי Player במסמכי העזרה של ExoPlayer מוסבר איך יוצרים מאזין ומשתמשים בו.
חשוב לזכור שממשק המאזין לא כולל קריאות חזרה (callbacks) למעקב אחרי התקדמות רגילה של ההפעלה. כדי לעקוב באופן רציף אחרי התקדמות ההפעלה, למשל כדי להגדיר ממשק משתמש של סרגל התקדמות, צריך לשלוח שאילתה לגבי המיקום הנוכחי במרווחי זמן מתאימים.
Kotlin
val handler = Handler(Looper.getMainLooper()) fun checkPlaybackPosition(delayMs: Long): Boolean = handler.postDelayed( { val currentPosition = player.currentPosition // Update UI based on currentPosition checkPlaybackPosition(delayMs) }, delayMs)
Java
Handler handler = new Handler(Looper.getMainLooper()); boolean checkPlaybackPosition(long delayMs) { return handler.postDelayed(() -> { long currentPosition = player.getCurrentPosition(); // Update UI based on currentPosition checkPlaybackPosition(delayMs); }, delayMs); }
שליטה בהפעלה
בממשק Player
יש הרבה דרכים לשנות את המצב ולשלוט בהפעלה:
- פקדי הפעלה בסיסיים כמו
play()
, pause()
, prepare()
ו-stop()
. - פעולות בפלייליסט כמו
addMediaItem()
אוremoveMediaItem()
. - דילוג כדי לשנות את המיקום או את הפריט הנוכחי.
- מגדירים מצבי חזרה ומצב הפעלה אקראית.
- מעדכנים את ההעדפות לבחירת טראקים.
- מגדירים את מהירות ההפעלה.
הטמעות בהתאמה אישית של Player
כדי ליצור נגן בהתאמה אישית, אפשר להרחיב את ה-SimpleBasePlayer
שכלול ב-Media3. המחלקה הזו מספקת הטמעה בסיסית של הממשק Player
כדי לצמצם את מספר השיטות שצריך להטמיע למינימום.
מתחילים על ידי שינוי השיטה getState()
. כשמפעילים את השיטה הזו, היא אמורה לאכלס את המצב הנוכחי של השחקן, כולל:
- קבוצת הפקודות הזמינות
- מאפייני ההפעלה, כמו אם הנגן צריך להתחיל להפעיל כשמצב ההפעלה הוא
STATE_READY
, המדד של פריט המדיה שפועל כרגע ומיקום ההפעלה בתוך הפריט הנוכחי
Kotlin
class CustomPlayer : SimpleBasePlayer(looper) { override fun getState(): State { return State.Builder() .setAvailableCommands(...) // Set which playback commands the player can handle // Configure additional playback properties .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST) .setCurrentMediaItemIndex(0) .setContentPositionMs(0) .build() } }
Java
public class CustomPlayer extends SimpleBasePlayer { public CustomPlayer(Looper looper) { super(looper); } @Override protected State getState() { return new State.Builder() .setAvailableCommands(...) // Set which playback commands the player can handle // Configure additional playback properties .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST) .setCurrentMediaItemIndex(0) .setContentPositionMs(0) .build(); } }
SimpleBasePlayer
יאלץ את State
להיווצר עם שילוב תקין של ערכי המצב. הוא גם יטפל במאזינים ויודיע להם על שינויים במצב. אם צריך להפעיל עדכון מצב באופן ידני, צריך להתקשר למספר invalidateState()
.
מלבד השיטה getState()
, צריך להטמיע רק שיטות שמשמשות לפקודות שהנגן מצהיר שהן זמינות. מאתרים את שיטת הטיפול שניתנת לשינוי שתואמת לפונקציונליות שרוצים להטמיע. לדוגמה, אפשר לשנות את השיטה handleSeek()
כדי לתמוך בפעולות כמו COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM
ו-COMMAND_SEEK_TO_NEXT_MEDIA_ITEM
.