ממשק הנגן

נגן הוא הרכיב באפליקציה שמאפשר הפעלה של קובצי מדיה. הממשק Player של Media3 מגדיר את הפונקציונליות שבדרך כלל מטופלת על ידי נגן. זה כולל:

  • השפעה על רכיבי ה-UI להפעלה, כמו הפעלה, השהיה וחיפוש
  • שליחת שאילתות לגבי מאפיינים של המדיה שמופעלת כרגע, כמו מיקום ההפעלה
  • ניהול פלייליסט או תור של קובצי מדיה
  • הגדרת מאפייני הפעלה, כמו הפעלה בסדר אקראי, הפעלה חוזרת, מהירות ועוצמת קול
  • עיבוד הסרטון למסך

ב-Media3 יש גם הטמעה של הממשק Player, שנקראת ExoPlayer.

ממשק משותף בין רכיבים

כמה רכיבים ב-Media3 מטמיעים את ממשק הנגן, לדוגמה:

רכיב תיאור והערות לגבי ההתנהגות
ExoPlayer ממשק API של נגן מדיה, וההטמעה שמוגדרת כברירת מחדל של הממשק Player.
MediaController אינטראקציה עם MediaSession כדי לשלוח פקודות הפעלה. אם Player ו-MediaSession נמצאים ב- Service נפרד מ-Activity או מ-Fragment שבהם נמצא ממשק המשתמש של הנגן, אפשר להקצות את MediaController כנגן של רכיב ממשק המשתמש כמו PlayerView או Player Composable. הפעלות של method להפעלה ולפלייליסט נשלחות אל Player דרך MediaSession.
MediaBrowser בנוסף לפונקציונליות של MediaController, מקיים אינטראקציה עם MediaLibrarySession כדי לעיין בתוכן מדיה זמין.
SimpleBasePlayer הטמעה של Player שמצמצמת למינימום את מספר השיטות שצריך להטמיע. האפשרות הזו שימושית כשרוצים לחבר נגן מותאם אישית ל-MediaSession.
ForwardingSimpleBasePlayer מחלקה משנית של SimpleBasePlayer שנועדה להעביר פעולות הפעלה ל-Player אחר, תוך מתן אפשרות לאותן התאמות אישיות של התנהגות עקבית כמו SimpleBasePlayer. אפשר להשתמש במחלקה הזו כדי להשתיק או לשנות פעולות הפעלה ספציפיות.
RemoteCastPlayer הטמעה של Player לשליטה בהפעלה באפליקציית Cast Receiver מרוחקת.
CastPlayer הטמעה של Player לשליטה בהפעלה מקומית ומרחוק של Cast.

למרות ש-MediaSession לא מטמיע את הממשק Player, הוא דורש Player כשיוצרים אותו. המטרה שלו היא לספק גישה ל-Player מתהליכים או משרשורים אחרים.

ארכיטקטורת ההפעלה של Media3

אם יש לכם גישה ל-Player, אתם צריכים להפעיל את השיטות שלו ישירות כדי להנפיק פקודות הפעלה. כדי לפרסם את ההפעלה שלכם ולתת למקורות חיצוניים שליטה בהפעלה, אתם יכולים להטמיע MediaSession. המקורות החיצוניים האלה מטמיעים MediaController, שמאפשר להתחבר לסשן מדיה ולשלוח בקשות לפקודות הפעלה.

כשמפעילים מדיה ברקע, צריך לאחסן את סשן המדיה ואת הנגן בתוך MediaSessionService או MediaLibraryService שפועלים כשירות בחזית. כך תוכלו להפריד בין הנגן לבין ה-Activity באפליקציה שמכילה את רכיבי ה-UI להפעלה. יכול להיות שתצטרכו להשתמש בממשק השליטה במדיה.

תרשים שמראה איך רכיבי ההפעלה של Media3 משתלבים בארכיטקטורה של אפליקציית מדיה.
איור 1: לממשק Player יש תפקיד מרכזי בארכיטקטורה של Media3.

מצב הנגן

המצב של נגן מדיה שמטמיע את הממשק Player מורכב בעיקר מ-4 קטגוריות של מידע:

  1. מצב ההפעלה
  2. פלייליסט של קובצי מדיה
  3. מאפייני הפעלה/השהיה, כמו:
    • ‫playWhenReady: אינדיקציה אם המשתמש רוצה שהמדיה תופעל כשאפשר או תישאר מושהית
    • סיבה לביטול ההפעלה: אינדיקציה לסיבה שבגללה ההפעלה בוטלה, אם רלוונטי, גם אם הערך של playWhenReady הוא true
    • isPlaying: אינדיקציה אם הנגן פועל כרגע. הערך יהיה true רק אם מצב ההפעלה הוא STATE_READY, הערך של playWhenReady הוא true וההפעלה לא מושהית.
  4. מיקום ההפעלה, כולל:

בנוסף, הממשק של Player מאפשר גישה לטראקים הזמינים, למטא-נתונים של המדיה, למהירות ההפעלה, לעוצמת הקול ולמאפייני עזר אחרים של ההפעלה.

האזנה לשינויים

משתמשים ב-Player.Listener כדי להאזין לשינויים ב-Player. במסמכי התיעוד של ExoPlayer בנושא אירועים של נגן מוסבר איך ליצור מאזין ולהשתמש בו.

שימו לב שממשק המאזין לא כולל קריאות חוזרות (callbacks) למעקב אחרי התקדמות ההפעלה הרגילה. כדי לעקוב באופן רציף אחרי התקדמות ההפעלה, למשל כדי להגדיר ממשק משתמש של סרגל התקדמות, צריך לשלוח שאילתה לגבי המיקום הנוכחי במרווחי זמן מתאימים.

Kotlin

fun checkPlaybackPosition(delayMs: Long): Boolean =
  handler.postDelayed(
    {
      val currentPosition = player.currentPosition
      // Update UI based on currentPosition
      checkPlaybackPosition(delayMs)
    },
    delayMs,
  )

Java

boolean checkPlaybackPosition(long delayMs) {
  return handler.postDelayed(
      () -> {
        long currentPosition = player.getCurrentPosition();
        // Update UI based on currentPosition
        checkPlaybackPosition(delayMs);
      },
      delayMs);
}

שליטה בהפעלה

הממשק Player מציע דרכים רבות לשנות את המצב ולשלוט בהפעלה:

הטמעות בהתאמה אישית של Player

כדי ליצור נגן מותאם אישית, אתם יכולים להרחיב את SimpleBasePlayer שכלול ב-Media3. המחלקה הזו מספקת הטמעה בסיסית של הממשק Player כדי לצמצם למינימום את מספר השיטות שצריך להטמיע.

קודם כול, צריך לשנות את השיטה getState(). השיטה הזו צריכה לאכלס את מצב הנגן הנוכחי כשהיא מופעלת, כולל:

  • קבוצת הפקודות הזמינות
  • מאפייני הפעלה, כמו אם הנגן צריך להתחיל לפעול כשמצב ההפעלה הוא STATE_READY, האינדקס של קובץ המדיה שמופעל כרגע ומיקום ההפעלה בתוך הפריט הנוכחי

Kotlin

class CustomPlayer(looper: Looper) : SimpleBasePlayer(looper) {
  override fun getState(): State {
    return State.Builder()
      .setAvailableCommands(Commands.EMPTY) // 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

private static final class CustomPlayer extends SimpleBasePlayer {
  public CustomPlayer(Looper looper) {
    super(looper);
  }

  @Override
  protected State getState() {
    return new State.Builder()
        .setAvailableCommands(Commands.EMPTY) // 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().

מעבר ל-method‏ getState(), אתם צריכים להטמיע רק methods שמשמשים לפקודות שהנגן שלכם מצהיר שהן זמינות. מוצאים את שיטת ה-handler שניתנת לשינוי, שתואמת לפונקציונליות שרוצים להטמיע. לדוגמה, אפשר לשנות את השיטה handleSeek() כדי לתמוך בפעולות כמו COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM ו-COMMAND_SEEK_TO_NEXT_MEDIA_ITEM.

שינוי ההטמעות של Player

במקום ליצור Player בהתאמה אישית מלאה, אתם יכולים להשתמש ב-ForwardingSimpleBasePlayer כדי לשנות את המצב וההתנהגות של Player קיים. פרטים נוספים זמינים במדריך שבדף ההתאמה האישית.