כדי להשלים את התכנון של הלקוח/שרת, יש ליצור רכיב פעילות שמכיל את קוד ממשק המשתמש שלכם, MediaController המשויך ו-MediaBrowser.
ה-MediaBrowser מבצע שתי פונקציות חשובות: הוא מתחבר אל MediaBrowserService ולאחר החיבור שלו יוצר את MediaController עבור ממשק המשתמש שלכם.
הערה: ההטמעה המומלצת של MediaBrowser
היא MediaBrowserCompat
,
שמוגדר
ספריית התמיכה לתאימות מדיה.
בכל הדף הזה מופיע המונח "MediaBrowser" מתייחס למופע
של MediaBrowserCompat.
התחברות אל MediaBrowserService
כשנוצרת פעילות של לקוח, היא מתחברת אל MediaBrowserService. התהליך כולל קצת לחיצת יד וריקוד. משנים את הקריאות החוזרות (callback) של מחזור החיים של הפעילות באופן הבא:
onCreate()
בונה MediaBrowserCompat. מעבירים את השם של MediaBrowserService ושל MediaBrowserCompat.ConnectionCallback שהגדרתם.onStart()
מתחבר אל MediaBrowserService. כאן נכנס לתוקף הקסם של MediaBrowserCompat.ConnectionCallback. אם החיבור מתבצע בהצלחה, הקריאה החוזרת של onConnect() יוצרת את בקר המדיה, מקשרת אותו להפעלת המדיה, מקשרת את פקדי ממשק המשתמש ל-MediaController, ורושמת את הבקר כדי לקבל קריאות חוזרות מסשן המדיה.onResume()
מגדיר את שידור האודיו כך שהאפליקציה מגיבה לבקרת עוצמת הקול במכשיר.onStop()
מנתק את MediaBrowser ומבטל את הרישום של MediaController.Callback כשהפעילות מופסקת.
Kotlin
class MediaPlayerActivity : AppCompatActivity() { private lateinit var mediaBrowser: MediaBrowserCompat override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... // Create MediaBrowserServiceCompat mediaBrowser = MediaBrowserCompat( this, ComponentName(this, MediaPlaybackService::class.java), connectionCallbacks, null // optional Bundle ) } public override fun onStart() { super.onStart() mediaBrowser.connect() } public override fun onResume() { super.onResume() volumeControlStream = AudioManager.STREAM_MUSIC } public override fun onStop() { super.onStop() // (see "stay in sync with the MediaSession") MediaControllerCompat.getMediaController(this)?.unregisterCallback(controllerCallback) mediaBrowser.disconnect() } }
Java
public class MediaPlayerActivity extends AppCompatActivity { private MediaBrowserCompat mediaBrowser; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... // Create MediaBrowserServiceCompat mediaBrowser = new MediaBrowserCompat(this, new ComponentName(this, MediaPlaybackService.class), connectionCallbacks, null); // optional Bundle } @Override public void onStart() { super.onStart(); mediaBrowser.connect(); } @Override public void onResume() { super.onResume(); setVolumeControlStream(AudioManager.STREAM_MUSIC); } @Override public void onStop() { super.onStop(); // (see "stay in sync with the MediaSession") if (MediaControllerCompat.getMediaController(MediaPlayerActivity.this) != null) { MediaControllerCompat.getMediaController(MediaPlayerActivity.this).unregisterCallback(controllerCallback); } mediaBrowser.disconnect(); } }
התאמה אישית של MediaBrowserCompat.ConnectionCallback
כשהפעילות שלכם יוצרת את MediaBrowserCompat, עליכם ליצור מופע של ConnectionCallback. משנים את השיטה onConnected()
כדי לאחזר את האסימון של סשן המדיה מה-MediaBrowserService ומשתמשים באסימון כדי ליצור MediaControllerCompat.
שימוש בשיטת הנוחות
MediaControllerCompat.setMediaController()
כדי לשמור קישור לבקר אחר. כך ניתן להשתמש בלחצני מדיה. הוא גם מאפשר להתקשר
MediaControllerCompat.getMediaController()
כדי לאחזר את הבקר במהלך פיתוח אמצעי בקרת התעבורה.
דוגמת הקוד הבאה מראה איך לשנות את השיטה onConnected()
.
Kotlin
private val connectionCallbacks = object : MediaBrowserCompat.ConnectionCallback() { override fun onConnected() { // Get the token for the MediaSession mediaBrowser.sessionToken.also { token -> // Create a MediaControllerCompat val mediaController = MediaControllerCompat( this@MediaPlayerActivity, // Context token ) // Save the controller MediaControllerCompat.setMediaController(this@MediaPlayerActivity, mediaController) } // Finish building the UI buildTransportControls() } override fun onConnectionSuspended() { // The Service has crashed. Disable transport controls until it automatically reconnects } override fun onConnectionFailed() { // The Service has refused our connection } }
Java
private final MediaBrowserCompat.ConnectionCallback connectionCallbacks = new MediaBrowserCompat.ConnectionCallback() { @Override public void onConnected() { // Get the token for the MediaSession MediaSessionCompat.Token token = mediaBrowser.getSessionToken(); // Create a MediaControllerCompat MediaControllerCompat mediaController = new MediaControllerCompat(MediaPlayerActivity.this, // Context token); // Save the controller MediaControllerCompat.setMediaController(MediaPlayerActivity.this, mediaController); // Finish building the UI buildTransportControls(); } @Override public void onConnectionSuspended() { // The Service has crashed. Disable transport controls until it automatically reconnects } @Override public void onConnectionFailed() { // The Service has refused our connection } };
חיבור ממשק המשתמש לבקר המדיה
בקוד לדוגמה של ConnectionCallback שלמעלה, כולל קריאה ל-buildTransportControls()
לעדכון ממשק המשתמש שלך. צריך להגדיר את onClickListeners לרכיבי ממשק המשתמש ששולטים בנגן. בוחרים את האפשרות המתאימה
MediaControllerCompat.TransportControls
לכל אחד מהם.
הקוד שלכם ייראה בערך כך, עם onClickListener לכל לחצן:
Kotlin
fun buildTransportControls() { val mediaController = MediaControllerCompat.getMediaController(this@MediaPlayerActivity) // Grab the view for the play/pause button playPause = findViewById<ImageView>(R.id.play_pause).apply { setOnClickListener { // Since this is a play/pause button, you'll need to test the current state // and choose the action accordingly val pbState = mediaController.playbackState.state if (pbState == PlaybackStateCompat.STATE_PLAYING) { mediaController.transportControls.pause() } else { mediaController.transportControls.play() } } } // Display the initial state val metadata = mediaController.metadata val pbState = mediaController.playbackState // Register a Callback to stay in sync mediaController.registerCallback(controllerCallback) }
Java
void buildTransportControls() { // Grab the view for the play/pause button playPause = (ImageView) findViewById(R.id.play_pause); // Attach a listener to the button playPause.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Since this is a play/pause button, you'll need to test the current state // and choose the action accordingly int pbState = MediaControllerCompat.getMediaController(MediaPlayerActivity.this).getPlaybackState().getState(); if (pbState == PlaybackStateCompat.STATE_PLAYING) { MediaControllerCompat.getMediaController(MediaPlayerActivity.this).getTransportControls().pause(); } else { MediaControllerCompat.getMediaController(MediaPlayerActivity.this).getTransportControls().play(); } }); MediaControllerCompat mediaController = MediaControllerCompat.getMediaController(MediaPlayerActivity.this); // Display the initial state MediaMetadataCompat metadata = mediaController.getMetadata(); PlaybackStateCompat pbState = mediaController.getPlaybackState(); // Register a Callback to stay in sync mediaController.registerCallback(controllerCallback); } }
ה-methods של TransportControls שולחות קריאות חוזרות לסשן המדיה של השירות. חשוב לוודא שהגדרתם
שיטה MediaSessionCompat.Callback
לכל אמצעי בקרה.
נשארים מעודכנים עם סשן המדיה
ממשק המשתמש צריך להציג את המצב הנוכחי של סשן המדיה, כפי שמתואר על ידי מצב ההפעלה והמטא-נתונים שלו. כשיוצרים את אמצעי הבקרה, אפשר לראות את המצב הנוכחי של הסשן, להציג אותו בממשק המשתמש ולהפעיל או להשבית את אמצעי הבקרה על התחבורה על סמך המדינה והפעולות הזמינות בה.
כדי לקבל קריאות חוזרות מסשן המדיה בכל פעם שהמצב או המטא-נתונים שלו משתנים, צריך להגדיר
MediaControllerCompat.Callback
, בשתי השיטות האלה:
Kotlin
private var controllerCallback = object : MediaControllerCompat.Callback() { override fun onMetadataChanged(metadata: MediaMetadataCompat?) {} override fun onPlaybackStateChanged(state: PlaybackStateCompat?) {} }
Java
MediaControllerCompat.Callback controllerCallback = new MediaControllerCompat.Callback() { @Override public void onMetadataChanged(MediaMetadataCompat metadata) {} @Override public void onPlaybackStateChanged(PlaybackStateCompat state) {} };
רושמים את הקריאה החוזרת (callback) כשמפתחים את אמצעי בקרת התעבורה (ראו השיטה buildTransportControls()
) ומבטלים את הרישום כשהפעילות נפסקת (בשיטת מחזור החיים onStop()
של הפעילות).
התנתקות כשסשן המדיה מושמד
אם סשן המדיה הופך ללא תקין,
onSessionDestroyed()
מתבצעת קריאה חוזרת. כשזה קורה, הסשן לא יכול לפעול.
שוב במהלך משך החיים של MediaBrowserService
. למרות שהפונקציות
שקשורים אל MediaBrowser
עשויים להמשיך לפעול, משתמשים לא יכולים לצפות או לשלוט
מסשן מדיה שהושמד, דבר שעלול לגרום לירידה בערך של
את האפליקציה שלך.
לכן, כשהסשן מושמד, חובה להתנתק
MediaBrowserService
בשיחה
disconnect()
הדבר מבטיח שלשירות הדפדפן אין לקוחות קשורים
ניתן להרוס אותו
מערכת ההפעלה.
אם צריך להתחבר מחדש אל MediaBrowserService
מאוחר יותר (לדוגמה,
אם האפליקציה רוצה לשמור על חיבור יציב לאפליקציית המדיה),
ליצור מופע חדש של MediaBrowser
במקום להשתמש שוב במופע הישן.
קטע הקוד הבא מדגים הטמעת קריאה חוזרת (callback) מתנתק משירות הדפדפן כאשר פעילות המדיה נמחקת:
Kotlin
private var controllerCallback = object : MediaControllerCompat.Callback() { override fun onSessionDestroyed() { mediaBrowser.disconnect() // maybe schedule a reconnection using a new MediaBrowser instance } }
Java
MediaControllerCompat.Callback controllerCallback = new MediaControllerCompat.Callback() { @Override public void onSessionDestroyed() { mediaBrowser.disconnect(); // maybe schedule a reconnection using a new MediaBrowser instance } };