Mit einer Medien-App verbinden

Es gibt zwei Möglichkeiten, eine Verbindung zu einer Medien-App herzustellen:

  1. MediaController
  2. MediaBrowser

MediaController

Ein Media Controller interagiert mit einer Media Session, um die Wiedergabe einer Medien-App abzufragen und zu steuern. In Media3 implementiert die MediaController API die Player-Schnittstelle. Beispiele für Client-Apps, die einen MediaController verwenden:

Ein Media Controller kann auch in einer Medien-App nützlich sein, z. B. wenn sich der Player und die Mediensitzung in einem Service befinden, der sich von der Activity oder dem Fragment mit der Benutzeroberfläche unterscheidet.

MediaController erstellen

Wenn Sie einen MediaController erstellen möchten, müssen Sie zuerst einen SessionToken für den entsprechenden MediaSession erstellen. Die Methode onStart() von Activity oder Fragment kann dafür ein guter Ort sein.

Kotlin

val sessionToken = SessionToken(context, ComponentName(context, PlaybackService::class.java))

Java

SessionToken sessionToken =
    new SessionToken(context, new ComponentName(context, PlaybackService.class));

Wenn Sie mit diesem SessionToken dann einen MediaController erstellen, wird der Controller mit der angegebenen Sitzung verbunden. Dies geschieht asynchron. Sie sollten also auf das Ergebnis warten und es verwenden, sobald es verfügbar ist.

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 verwenden

MediaController implementiert die Player-Schnittstelle, sodass du die in der Schnittstelle definierten Befehle verwenden kannst, um die Wiedergabe des verbundenen MediaSession zu steuern. Das bedeutet, dass beim Aufrufen von play() für ein MediaController der Befehl an das verbundene MediaSession gesendet wird, das den Befehl dann an das zugrunde liegende Player delegiert.

Sie können dem Controller einen Player.Listener hinzufügen, um auf Änderungen des Player-Status zu reagieren. Weitere Informationen zur Verwendung eines Player.Listener findest du im Leitfaden zu Player-Ereignissen.

Die MediaController.Listener-Schnittstelle definiert zusätzliche Callbacks für Ereignisse und benutzerdefinierte Befehle vom verbundenen MediaSession. Beispiele sind onCustomCommand(), wenn die Sitzung einen benutzerdefinierten Befehl sendet, onAvailableSessionCommandsChanged(), wenn die Sitzung die verfügbaren Sitzungsbefehle ändert, oder onDisconnected(), wenn der Controller von der Sitzung getrennt wird.

Ein MediaController.Listener kann beim Erstellen des Controllers mit einem Builder festgelegt werden:

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();

Wie bei anderen Komponenten auch, müssen Sie den MediaController freigeben, wenn er nicht mehr benötigt wird, z. B. in der Methode onStop() einer Activity oder eines Fragment.

Kotlin

MediaController.releaseFuture(controllerFuture)

Java

MediaController.releaseFuture(controllerFuture);

Wenn der Controller freigegeben wird, werden alle ausstehenden Befehle, die an die Sitzung gesendet wurden, weiterhin zugestellt. Die Bindung an den Sitzungsdienst wird erst aufgehoben, wenn diese Befehle verarbeitet wurden oder ein Zeitlimit abgelaufen ist, je nachdem, was zuerst eintritt.

MediaBrowser

Ein MediaBrowser baut auf den Funktionen eines MediaController auf und ermöglicht auch das Durchsuchen der Mediathek, die von der MediaLibraryService einer Medien-App angeboten wird.

MediaBrowser erstellen

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 verwenden

Wenn du die Inhaltsbibliothek der Medien-App durchsuchen möchtest, rufe zuerst den Stammknoten mit getLibraryRoot() ab:

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());

Anschließend kannst du durch die Mediathek navigieren, indem du die untergeordneten Elemente eines MediaItem in der Mediathek mit getChildren() abrufst. So rufen Sie beispielsweise die untergeordneten Elemente des Stammknotens MediaItem ab:

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());

Wiedergabesteuerung für eine andere Medien-App anzeigen

Wenn du UI-Steuerelemente mit Schaltflächen für eine andere Medien-App anzeigst, ist es wichtig, die deklarierten Einstellungen für Medienschaltflächen dieser App zu beachten.

Verwenden Sie CommandButton.DisplayConstraints, um die Einstellungen der App mit den Einschränkungen und Anforderungen Ihrer Benutzeroberfläche abzugleichen. Sie können die Limits und Einschränkungen Ihrer UI definieren. Die Methode resolve() bietet eine Liste von Schaltflächen, die mit ihrem Symbol, ihrer Position und ihrer beabsichtigten Aktion angezeigt werden sollen. Wenn ein Nutzer auf eine dieser Schaltflächen klickt, kannst du mit CommandButton.executeAction die zugehörige Aktion in der Medien-App auslösen.

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));
}