连接到媒体应用

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

媒体控制器在媒体应用中也很有用,例如,如果播放器和媒体会话位于与 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

MediaBrowser 基于 MediaController 提供的功能构建,还可用于浏览媒体应用的 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());

显示其他媒体应用的播放控件

在显示包含其他媒体应用按钮的界面控件时,请务必遵循该应用声明的媒体按钮偏好设置

解决应用偏好设置与界面限制和要求之间冲突的最佳方法是使用 CommandButton.DisplayConstraints。您可以定义界面可以执行的操作的限制,而 resolve 方法会提供要显示的按钮的明确列表,其中包含按钮的图标、位置和预期操作。