יש שתי דרכים להתחבר לאפליקציית מדיה:
MediaControllerMediaBrowser
MediaController
ממשק השליטה במדיה יוצר אינטראקציה עם סשן מדיה כדי לשלוח שאילתות לאפליקציית מדיה ולשלוט בהפעלה שלה. ב-Media3, ה-API של MediaController מטמיע את הממשק Player. דוגמאות לאפליקציות לקוח שמשתמשות בממשק השליטה במדיה:
- ממשק השליטה במדיה של מערכת Android
- האפליקציה הנלווית של Android Wear OS
- Android Auto ו-Automotive OS
- עוזרים קוליים, כמו Google Assistant
- אפליקציית הבדיקה Media Controller
ממשק השליטה במדיה יכול להיות שימושי גם באפליקציית מדיה, למשל אם הנגן וסשן המדיה נמצאים ב-Service נפרד מה-Activity או מה-Fragment עם ממשק המשתמש.
צור MediaController
כדי ליצור MediaController, קודם צריך ליצור SessionToken ל-MediaSession המתאים. השיטה onStart() של Activity או Fragment יכולה להתאים לכך.
Kotlin
val sessionToken = SessionToken(context, ComponentName(context, PlaybackService::class.java))
Java
SessionToken sessionToken = new SessionToken(context, new ComponentName(context, PlaybackService.class));
שימוש ב-SessionToken הזה כדי ליצור MediaController מחבר את הבקר לסשן הנתון. הפעולה הזו מתבצעת באופן אסינכרוני, לכן צריך להאזין לתוצאה ולהשתמש בה כשהיא זמינה.
Kotlin
val controllerFuture = MediaController.Builder(context, sessionToken).buildAsync() controllerFuture.addListener( { // MediaController is available here with controllerFuture.get() }, MoreExecutors.directExecutor(), )
Java
ListenableFuture<MediaController> controllerFuture = new MediaController.Builder(context, sessionToken).buildAsync(); controllerFuture.addListener( () -> { // MediaController is available here with controllerFuture.get() }, MoreExecutors.directExecutor());
שימוש בMediaController
MediaController מטמיע את הממשק Player, כך שאפשר להשתמש בפקודות שמוגדרות בממשק כדי לשלוט בהפעלה של MediaSession המחובר.
כלומר, קריאה ל-play() ב-MediaController תשלח את הפקודה ל-MediaSession המחובר, שיעביר את הפקודה ל-Player הבסיסי שלו.
אפשר להוסיף Player.Listener לבקר כדי להאזין לשינויים במצב של Player. במדריך בנושא אירועים של נגן מפורט מידע נוסף על השימוש ב-Player.Listener.
הממשק MediaController.Listener מגדיר קריאות חוזרות (callbacks) נוספות לאירועים ולפקודות בהתאמה אישית מה-MediaSession המחובר. לדוגמה,
onCustomCommand() כשהסשן שולח פקודה בהתאמה אישית,
onAvailableSessionCommandsChanged() כשהסשן משנה את פקודות הסשן
הזמינות או onDisconnected() כשהבקר מנותק
מהסשן.
אפשר להגדיר MediaController.Listener כשיוצרים את הבקר באמצעות Builder:
Kotlin
val controllerFuture = MediaController.Builder(context, sessionToken) .setListener( object : MediaController.Listener { override fun onCustomCommand( controller: MediaController, command: SessionCommand, args: Bundle, ): ListenableFuture<SessionResult> { // Handle custom command. return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS)) } override fun onDisconnected(controller: MediaController) { // Handle disconnection. } } ) .buildAsync()
Java
ListenableFuture<MediaController> controllerFuture = new MediaController.Builder(context, sessionToken) .setListener( new MediaController.Listener() { @Override public ListenableFuture<SessionResult> onCustomCommand( MediaController controller, SessionCommand command, Bundle args) { // Handle custom command. return Futures.immediateFuture(new SessionResult(SessionResult.RESULT_SUCCESS)); } @Override public void onDisconnected(MediaController controller) { // Handle disconnection. } }) .buildAsync();
כמו ברכיבים אחרים, חשוב לשחרר את ה-MediaController כשכבר לא צריך אותו, למשל ב-method onStop() של Activity או Fragment.
Kotlin
MediaController.releaseFuture(controllerFuture)
Java
MediaController.releaseFuture(controllerFuture);
גם אם משחררים את הבקר, כל הפקודות שנשלחו לסשן ועדיין לא בוצעו יועברו, וההתנתקות משירות הסשן תתבצע רק אחרי שהפקודות האלה יטופלו או אחרי פרק זמן קצוב, המוקדם מביניהם.
MediaBrowser
MediaBrowser מתבסס על היכולות של MediaController כדי לאפשר גם עיון בספריית המדיה שמוצעת על ידי MediaLibraryService של אפליקציית מדיה.
צור MediaBrowser
Kotlin
val browserFuture = MediaBrowser.Builder(context, sessionToken).buildAsync() browserFuture.addListener( { // MediaBrowser is available here with browserFuture.get() }, MoreExecutors.directExecutor(), )
Java
ListenableFuture<MediaBrowser> browserFuture = new MediaBrowser.Builder(context, sessionToken).buildAsync(); browserFuture.addListener( () -> { // MediaBrowser is available here with browserFuture.get() }, MoreExecutors.directExecutor());
שימוש בMediaBrowser
כדי להתחיל לעיין בספריית התוכן של אפליקציית המדיה, קודם צריך לאחזר את צומת הבסיס באמצעות getLibraryRoot():
Kotlin
// Get the library root to start browsing the library tree. val rootFuture = mediaBrowser.getLibraryRoot(/* params= */ null) rootFuture.addListener( { // Root node MediaItem is available here with rootFuture.get().value }, MoreExecutors.directExecutor(), )
Java
// Get the library root to start browsing the library tree. ListenableFuture<LibraryResult<MediaItem>> rootFuture = mediaBrowser.getLibraryRoot(/* params= */ null); rootFuture.addListener( () -> { // Root node MediaItem is available here with rootFuture.get().value }, MoreExecutors.directExecutor());
אחר כך אפשר לנווט בספריית המדיה על ידי אחזור הצאצאים של MediaItem בספרייה באמצעות getChildren(). לדוגמה, כדי לאחזר את הצאצאים של צומת הבסיס MediaItem:
Kotlin
// Get the library root to start browsing the library tree. val childrenFuture = mediaBrowser.getChildren(rootMediaItem.mediaId, 0, Int.MAX_VALUE, null) childrenFuture.addListener( { // List of children MediaItem nodes is available here with // childrenFuture.get().value }, MoreExecutors.directExecutor(), )
Java
ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> childrenFuture = mediaBrowser.getChildren(rootMediaItem.mediaId, 0, Integer.MAX_VALUE, null); childrenFuture.addListener( () -> { // List of children MediaItem nodes is available here with // childrenFuture.get().value }, MoreExecutors.directExecutor());
הצגת רכיבי ה-UI להפעלה של אפליקציית מדיה אחרת
כשמציגים רכיבים אינטראקטיביים עם כפתורים לאפליקציית מדיה אחרת, חשוב לפעול לפי העדפות כפתורי המדיה שהוגדרו באפליקציה הזו.
כדי לפתור את הבעיה של העדפות האפליקציה עם האילוצים והדרישות של ממשק המשתמש, צריך להשתמש ב-CommandButton.DisplayConstraints. אתם יכולים להגדיר את המגבלות וההגבלות של ממשק המשתמש, וה-method resolve() מספקת רשימה מוגדרת של כפתורים שיוצגו עם הסמל, המיקום והפעולה המיועדת שלהם. אם משתמש לוחץ על אחד מהלחצנים האלה, אפשר להשתמש ב-CommandButton.executeAction כדי להפעיל את הפעולה המשויכת באפליקציית המדיה.
Kotlin
// Get media button preferences from media app val mediaButtonPreferences = controller.getMediaButtonPreferences() // Declare constraints of UI (example: limit overflow button to one) val displayConstraints = DisplayConstraints.Builder().setMaxButtonsForSlot(CommandButton.SLOT_OVERFLOW, 1).build() // Resolve media app preferences with constraints val resolvedButtons = displayConstraints.resolve(mediaButtonPreferences, controller) // Display buttons in UI for (button in resolvedButtons) { generateUiButton( uiPosition = button.slots[0], icon = getIconRes(button.icon), onClick = { button.executeAction(controller) }, ) }
Java
// Get media button preferences from media app List<CommandButton> mediaButtonPreferences = controller.getMediaButtonPreferences(); // Declare constraints of UI (example: limit overflow button to one) DisplayConstraints displayConstraints = new DisplayConstraints.Builder() .setMaxButtonsForSlot(CommandButton.SLOT_OVERFLOW, 1) .build(); // Resolve media app preferences with constraints List<CommandButton> resolvedButtons = displayConstraints.resolve(mediaButtonPreferences, controller); // Display buttons in UI for (CommandButton button : resolvedButtons) { generateUiButton( /* uiPosition= */ button.slots.get(0), /* icon= */ getIconRes(button.icon), /* onClick= */ () -> button.executeAction(controller)); }