Mit einer Medien-App verbinden

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

  1. MediaController
  2. MediaBrowser

MediaController

Eine Mediensteuerung 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 Media Controller verwenden:

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

MediaController erstellen

Erstellen Sie zuerst ein SessionToken für die entsprechende MediaSession, um einen MediaController zu erstellen. Die Methode onStart() Ihrer Activity oder Ihres Fragment ist dafür gut geeignet.

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 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. Sie können also die in der Schnittstelle definierten Befehle verwenden, um die Wiedergabe der verbundenen MediaSession zu steuern. Wenn Sie play() für einen MediaController aufrufen, wird der Befehl an die verbundene MediaSession gesendet, die ihn dann an den zugrunde liegenden Player weiterleitet.

Sie können dem Controller einen Player.Listener hinzufügen, um auf Änderungen im Player Status zu warten. Weitere Informationen zur Verwendung von Player.Listener finden Sie im Leitfaden zu Player-Ereignissen.

Die MediaController.Listener-Schnittstelle definiert zusätzliche Callbacks für Ereignisse und benutzerdefinierte Befehle aus der verbundenen MediaSession. Beispiele sind onCustomCommand(), wenn die Sitzung einen benutzerdefinierten Befehl sendet, onAvailableSessionCommandsChanged(), wenn die Sitzung die verfügbaren Sitzungsbefehle ändert, oder onDisconnected(), wenn die Verbindung des Controllers zur 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 sollten 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 Sie den Controller freigeben, werden alle ausstehenden Befehle, die an die Sitzung gesendet wurden, weiterhin ausgeführt. Die Verbindung zum Sitzungsdienst wird erst getrennt, wenn diese Befehle verarbeitet wurden oder nach einem Timeout-Zeitraum, je nachdem, was zuerst eintritt.

MediaBrowser

Ein MediaBrowser baut auf den Funktionen eines MediaController auf und ermöglicht auch das Durchsuchen der Mediathek, die vom MediaLibraryService einer Media 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

Rufen Sie zuerst den Stammknoten mit getLibraryRoot() ab, um die Inhaltsbibliothek der Media App zu durchsuchen:

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 können Sie durch die Mediathek navigieren, indem Sie die untergeordneten Elemente eines MediaItem in der Mediathek mit getChildren() abrufen. 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 Media App anzeigen

Wenn Sie UI-Steuerelemente mit Schaltflächen für eine andere Media App anzeigen, müssen Sie die deklarierten Einstellungen für Medientasten dieser App berücksichtigen.

Verwenden Sie CommandButton.DisplayConstraints, um die Einstellungen der App mit den Einschränkungen und Anforderungen Ihrer Benutzeroberfläche abzugleichen. Sie können die Grenzen und Einschränkungen Ihrer Benutzeroberfläche definieren. Die resolve Methode liefert eine genaue Liste der Schaltflächen, die mit ihrem Symbol, ihrer Position und der beabsichtigten Aktion angezeigt werden sollen. Wenn ein Nutzer auf eine dieser Schaltflächen klickt, können Sie mit CommandButton.executeAction die zugehörige Aktion in der Media 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));
}