连接到媒体应用

媒体控制器与媒体会话交互,以查询和控制媒体应用的播放。在 Media3 中,MediaController API 实现了 Player 接口。使用媒体控制器的客户端应用示例包括:

媒体控制器在媒体应用中也很有用,例如,如果播放器和媒体会话位于一个与带有 UI 的 ActivityFragment 分开的 Service 中。

创建 MediaController

要创建 MediaController,首先为您对应的 MediaSession 创建一个 SessionTokenActivityFragmentonStart() 方法是执行此操作的好地方。

Kotlin

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

Java

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

使用此 SessionToken 构建 MediaController 会将控制器连接到给定会话。此过程是异步的,因此您应该监听结果并在可用时使用它。

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

MediaController 实现了 Player 接口,因此您可以使用接口中定义的命令来控制已连接的 MediaSession 的播放。也就是说,在 MediaController 上调用 play() 会将命令发送到已连接的 MediaSession,后者随后会将命令委托给其底层 Player

您可以向控制器添加一个 Player.Listener,以监听 Player 状态的变化。有关使用 Player.Listener 的更多详细信息,请参阅播放器事件指南。

MediaController.Listener 接口定义了来自已连接的 MediaSession 的事件和自定义命令的其他回调。例如,当会话发送自定义命令时会调用 onCustomCommand(),当会话更改可用会话命令时会调用 onAvailableSessionCommandsChanged(),或者当控制器与会话断开连接时会调用 onDisconnected()

使用 Builder 构建控制器时可以设置 MediaController.Listener

Kotlin

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

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

与其他组件一样,当不再需要 MediaController 时,请记住释放它,例如在 ActivityFragmentonStop() 方法中。

Kotlin

MediaController.releaseFuture(controllerFuture)

Java

MediaController.releaseFuture(controllerFuture);

释放控制器后仍会向会话传递所有待处理的命令,并且仅在这些命令得到处理后或在超时期限后(以先发生者为准)才会解除与会话服务的绑定。

创建和使用 MediaBrowser

MediaBrowserMediaController 提供的功能之上构建,还可以浏览媒体应用 MediaLibraryService 提供的媒体库。

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

要开始浏览媒体应用的内容库,首先使用 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());

然后,您可以通过使用 getChildren() 检索库中 MediaItem 的子项来导航媒体库。例如,要检索根节点 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());

显示另一个媒体应用的播放控件

当为另一个媒体应用显示带有按钮的 UI 控件时,遵循该应用声明的媒体按钮偏好设置非常重要。

解决应用偏好设置与您的 UI 约束和要求的最佳方法是使用 CommandButton.DisplayConstraints。您可以定义您的 UI 可以执行的限制,resolve 方法提供了一份明确的按钮列表,其中包含它们的图标、位置和预期操作。