Per completare la progettazione client/server, devi creare un componente attività che contenga il codice dell'interfaccia utente, un MediaController associato e un MediaBrowser.
MediaBrowser esegue due funzioni importanti: si connette a MediaBrowserService e, al momento della connessione, crea il MediaController per l'interfaccia utente.
Nota: l'implementazione consigliata di MediaBrowser
è MediaBrowserCompat
,
definito nel
libreria di supporto Media-Compat.
In questa pagina il termine "MediaBrowser" si riferisce a un'istanza
di MediaBrowserCompat.
Connettersi a MediaBrowserService
Quando viene creata l'attività client, questo si connette a MediaBrowserService. È prevista una stretta di mano e una danza. Modifica i callback del ciclo di vita dell'attività come segue:
onCreate()
genera un MediaBrowserCompat. Inserisci il nome di MediaBrowserService e MediaBrowserCompat.ConnectionCallback che hai definito.onStart()
si connette a MediaBrowserService. Ecco dove entra in gioco la magia di MediaBrowserCompat.ConnectionCallback. Se la connessione ha esito positivo, il callback onConnect() crea il controller multimediale, lo collega alla sessione multimediale, collega i controlli UI a MediaController e registra il controller per ricevere i callback dalla sessione multimediale.onResume()
imposta lo stream audio in modo che la tua app risponda al controllo del volume sul dispositivo.onStop()
disconnette il tuo MediaBrowser e annulla la registrazione di MediaController.Callback quando l'attività si interrompe.
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()
}
}
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();
}
}
Personalizza MediaBrowserCompat.ConnectionCallback
Quando l'attività genera MediaBrowserCompat, devi creare un'istanza di ConnectionCallback. Modifica il metodo onConnected()
per recuperare il token della sessione multimediale da MediaBrowserService e utilizzalo per creare un MediaControllerCompat.
Usa il metodo pratico
MediaControllerCompat.setMediaController()
per salvare un collegamento al controller. Consente di gestire i pulsanti multimediali. Ti permette anche di chiamare
MediaControllerCompat.getMediaController()
per recuperare il controller durante la creazione dei controlli di trasporto.
Il seguente esempio di codice mostra come modificare il metodo onConnected()
.
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
}
}
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
}
};
Collegare la UI al controller multimediale
Nel codice campione di ConnectionCallback riportato sopra, include una chiamata a buildTransportControls()
per arricchire la tua UI. Sarà necessario impostare un valore di offerto da stabilire per gli elementi dell'interfaccia utente che controllano il player. Scegli l'impostazione appropriata
MediaControllerCompat.TransportControls
metodo per ciascuno.
Il codice avrà un aspetto simile a questo, con un valore da scegliere per ciascun pulsante:
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)
}
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);
}
}
I metodi TransportControls inviano callback alla sessione multimediale del tuo servizio. Accertati di aver definito una
MediaSessionCompat.Callback
metodo per ogni controllo.
Sincronizzati con la sessione multimediale
Nella UI dovrebbe essere visualizzato lo stato corrente della sessione multimediale, come descritto da PlaybackState e dai relativi metadati. Quando crei controlli di trasporto, puoi acquisire lo stato attuale della sessione, visualizzarlo nell'interfaccia utente e abilitare e disabilitare i controlli di trasporto in base allo stato e alle relative azioni disponibili.
Per ricevere callback dalla sessione multimediale ogni volta che lo stato o i metadati cambiano, definisci una
MediaControllerCompat.Callback
, con questi due metodi:
private var controllerCallback = object : MediaControllerCompat.Callback() {
override fun onMetadataChanged(metadata: MediaMetadataCompat?) {}
override fun onPlaybackStateChanged(state: PlaybackStateCompat?) {}
}
MediaControllerCompat.Callback controllerCallback =
new MediaControllerCompat.Callback() {
@Override
public void onMetadataChanged(MediaMetadataCompat metadata) {}
@Override
public void onPlaybackStateChanged(PlaybackStateCompat state) {}
};
Registra il callback quando crei controlli di trasporto (vedi il metodo buildTransportControls()
) e annulla la registrazione quando l'attività si interrompe (nel metodo di ciclo di vita onStop()
dell'attività).
Disconnettiti quando la sessione multimediale viene eliminata
Se la sessione multimediale non è valida,
onSessionDestroyed()
il callback. In questo caso, la sessione non può diventare funzionante
di nuovo per la durata di MediaBrowserService
. Sebbene le funzioni
relative a MediaBrowser
potrebbero continuare a funzionare, un utente non può visualizzare o controllare
da una sessione multimediale eliminata, il che probabilmente ridurrà il valore
la tua applicazione.
Pertanto, quando la sessione viene eliminata, devi disconnetterti dalla
MediaBrowserService
chiamando
disconnect()
.
Ciò garantisce che il servizio browser non abbia client associati e
può essere distrutto
Sistema operativo.
Se devi riconnetterti a MediaBrowserService
in un secondo momento (ad esempio, se
l'applicazione vuole mantenere una connessione permanente all'app multimediale),
crea una nuova istanza di MediaBrowser
anziché riutilizzare quella precedente.
Il seguente snippet di codice illustra un'implementazione di callback che si disconnette dal servizio browser quando la sessione multimediale viene eliminata:
private var controllerCallback = object : MediaControllerCompat.Callback() {
override fun onSessionDestroyed() {
mediaBrowser.disconnect()
// maybe schedule a reconnection using a new MediaBrowser instance
}
}
MediaControllerCompat.Callback controllerCallback =
new MediaControllerCompat.Callback() {
@Override
public void onSessionDestroyed() {
mediaBrowser.disconnect();
// maybe schedule a reconnection using a new MediaBrowser instance
}
};