您可以通过以下两种方式连接到媒体应用:
MediaControllerMediaBrowser
MediaController
媒体控制器与媒体会话交互,以查询和控制媒体应用的播放。在 Media3 中,MediaController
API 实现了 Player 接口。使用媒体控制器的客户端应用示例包括:
- Android 系统媒体控件
- Android Wear OS 配套应用
- Android Auto 和 Automotive OS
- 语音助理,例如 Google 助理
- 媒体控制器测试应用
媒体控制器在媒体应用中也可能很有用,例如,如果播放器和媒体会话位于与界面所在的 Activity 或 Fragment 分开的 Service 中。
创建 MediaController
如需创建 MediaController,请先为相应的 MediaSession 创建 SessionToken。Activity 或 Fragment 的 onStart() 方法可能是一个不错的选择。
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
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();
与其他组件一样,请记得在不再需要 MediaController 时释放它,例如在 Activity 或 Fragment 的 onStop() 方法中。
Kotlin
MediaController.releaseFuture(controllerFuture)
Java
MediaController.releaseFuture(controllerFuture);
释放控制器后,系统仍会传送发送到会话的所有待处理命令,并且仅在这些命令处理完毕后或超时后(以先发生者为准)与会话服务取消绑定。
MediaBrowser
MediaBrowser 基于 MediaController 提供的功能构建,还支持浏览媒体应用的 MediaLibraryService 提供的媒体库。
创建 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());
使用 MediaBrowser
如需开始浏览媒体应用的内容库,请先使用 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 方法会提供要显示的按钮的明确列表,其中包含按钮的图标、位置和预期操作。如果用户点击其中一个按钮,您可以使用 CommandButton.executeAction 触发媒体应用中的关联操作。
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)); }