Há duas maneiras de se conectar a um app de música:
MediaControllerMediaBrowser
MediaController
Um controlador de mídia interage com uma sessão de mídia para consultar e controlar a reprodução de um app de música. No Media3, a API MediaController implementa a interface
Player. Exemplos de apps clientes que usam um controlador de mídia:
- Controles de mídia do sistema Android
- App complementar do Android Wear OS
- Android Auto e Automotive OS
- Assistentes por voz, como o Google Assistente
- O app de teste do controle de mídia
Um controlador de mídia também pode ser útil em um app de música, por exemplo, se o
player e a sessão de mídia estiverem em um Service separado do Activity ou
Fragment com a interface.
Criar um MediaController
Para criar um MediaController, comece criando um SessionToken para o
MediaSession correspondente. O método onStart() do seu Activity ou
Fragment pode ser um bom lugar para isso.
Kotlin
val sessionToken = SessionToken(context, ComponentName(context, PlaybackService::class.java))
Java
SessionToken sessionToken = new SessionToken(context, new ComponentName(context, PlaybackService.class));
Usar esse SessionToken para criar um MediaController conecta o
controlador à sessão em questão. Isso ocorre de forma assíncrona, então você precisa
detectar o resultado e usá-lo quando estiver disponível.
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());
Usar um MediaController
O MediaController implementa a interface Player para que você possa usar os comandos
definidos na interface para controlar a reprodução do MediaSession conectado.
Isso significa que chamar play() em um MediaController vai enviar o
comando para o MediaSession conectado, que vai delegar o
comando ao Player subjacente.
É possível adicionar um Player.Listener ao controlador para detectar mudanças no estado de
Player. Consulte o guia Eventos do player para mais detalhes sobre como usar um
Player.Listener.
A interface MediaController.Listener define callbacks adicionais para eventos
e comandos personalizados do MediaSession conectado. Exemplos são
onCustomCommand() quando a sessão envia um comando personalizado,
onAvailableSessionCommandsChanged() quando a sessão muda os comandos
disponíveis ou onDisconnected() quando o controlador é desconectado
da sessão.
É possível definir um MediaController.Listener ao criar o controlador com um
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();
Assim como em outros componentes, lembre-se de liberar o MediaController quando ele não for mais necessário, como no método onStop() de uma Activity ou Fragment.
Kotlin
MediaController.releaseFuture(controllerFuture)
Java
MediaController.releaseFuture(controllerFuture);
A liberação do controlador ainda vai entregar todos os comandos pendentes enviados para a sessão e só vai desvincular do serviço de sessão quando esses comandos forem processados ou após um período de tempo limite, o que ocorrer primeiro.
MediaBrowser
Um MediaBrowser se baseia nos recursos oferecidos por um
MediaController para também permitir a navegação na biblioteca de mídia oferecida pelo
MediaLibraryService de um app de música.
Criar um 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());
Usar um MediaBrowser
Para começar a navegar na biblioteca de conteúdo do app de música, primeiro recupere o nó raiz
com 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());
Em seguida, você pode navegar pela biblioteca de mídia recuperando os filhos de um
MediaItem na biblioteca com getChildren(). Por exemplo, para recuperar os
filhos do nó raiz 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());
Mostrar controles de mídia para outro app de música
Ao exibir controles de interface com botões para outro app de música, é importante seguir as preferências de botão de mídia declaradas desse app.
Para resolver as preferências do app com as restrições e os requisitos da
interface, use CommandButton.DisplayConstraints. É possível definir os limites e as
restrições da IU, e o método resolve()
fornece uma lista definitiva de botões para exibir com o ícone, a posição e
a ação pretendida. Se um usuário clicar em um desses botões, use
CommandButton.executeAction para acionar a ação associada no app
de música.
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)); }