媒体控制器通过与媒体会话互动来查询和控制媒体应用的播放。在 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
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
时释放它,例如在 Activity
或 Fragment
的 onStop()
方法中释放。
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
方法会提供要显示的按钮的明确列表,其中包含按钮的图标、位置和预期操作。