使用媒体会话

媒体会话提供了一种与音频或视频播放器交互的通用方式。通过通知 Android 应用中正在播放媒体,可以将播放控件委派给该应用。与媒体会话集成允许应用在外部宣传媒体播放并接收来自外部来源的播放命令。这些来源可以是物理按钮(例如耳机或电视遥控器上的播放按钮)或间接命令(例如指示 Google 助手“暂停”)。然后,媒体会话将这些命令委派给应用,该应用将这些命令应用于媒体播放器,对于这些命令的来源,它是透明的。

媒体会话与它管理的播放器并存。您应该在拥有媒体会话及其关联播放器的活动或服务的 onCreate() 方法中创建并初始化媒体会话。

初始化媒体会话

新创建的媒体会话没有任何功能。您必须通过执行以下步骤来初始化会话

  • 设置标志,以便媒体会话可以接收来自媒体控制器和媒体按钮的回调。
  • 创建并初始化 PlaybackStateCompat 的实例,并将其分配给会话。播放状态在整个会话期间都会发生变化,因此我们建议缓存 PlaybackStateCompat.Builder 以供重复使用。
  • 创建 MediaSessionCompat.Callback 的实例并将其分配给会话(有关回调的更多信息,请参见下文)。

您应该在拥有会话的 活动服务onCreate() 方法中创建并初始化媒体会话。

为了使 媒体按钮 在应用新初始化(或停止)时工作,其 PlaybackState 必须包含与媒体按钮发送的意图匹配的播放操作。这就是为什么在初始化期间将 ACTION_PLAY 分配给会话状态的原因。有关更多信息,请参阅 响应媒体按钮

维护播放状态和元数据

有两个类表示媒体会话的状态。

PlaybackStateCompat 类描述了播放器的当前操作状态。这包括

  • 传输状态(播放器是否正在播放/暂停/缓冲等。请参阅 getState()
  • 错误代码和可选错误消息(如果适用)。(请参阅 getErrorCode() 并阅读下面的 状态和错误。)
  • 播放器位置
  • 当前状态下可以处理的有效控制器操作

MediaMetadataCompat 类描述了正在播放的素材

  • 艺术家、专辑和曲目的名称
  • 曲目时长
  • 在锁定屏幕上显示的专辑插图。该图像是位图,最大尺寸为 320x320dp(如果更大,则会缩小)。
  • ContentUris 的实例,指向插图的更大版本

播放器状态和元数据在媒体会话的生命周期中可能会发生变化。每次状态或元数据发生变化时,您必须使用每个类的相应构建器 PlaybackStateCompat.Builder()MediaMetadataCompat.Builder(),然后通过调用 setPlaybackState()setMetaData() 将新实例传递给媒体会话。为了减少这些频繁操作带来的整体内存消耗,建议创建构建器一次并在会话的整个生命周期中重复使用它们。

状态和错误

请注意,PlaybackState 是一个对象,其中包含会话的播放状态 (getState()) 和在必要时关联的错误代码 (getErrorCode()) 的单独值。错误可能是致命的或非致命的

每当播放中断时,您都应该生成致命错误:将传输状态设置为 STATE_ERROR 并使用 setErrorMessage(int, CharSequence) 指定关联的错误。只要播放被错误阻止,PlaybackState 就应该继续报告 STATE_ERROR 和错误。

当您的应用无法处理请求但可以继续播放时,会发生非致命错误:传输保持在“正常”状态(例如 STATE_PLAYING),但 PlaybackState 包含错误代码。例如,如果正在播放最后一首歌曲,并且用户请求跳到下一首歌曲,则可以继续播放,但您应该创建一个新的 PlaybackState,其中包含错误代码 ERROR_CODE_END_OF_QUEUE,然后调用 setPlaybackState()。附加到会话的媒体控制器将接收回调 onPlaybackStateChanged() 并向用户解释发生了什么。非致命错误应该只在发生时报告一次。下次会话更新 PlaybackState 时,不要再次设置相同的非致命错误(除非错误是在响应新请求时发生的)。

媒体会话锁定屏幕

从 Android 4.0(API 级别 14)开始,系统可以访问媒体会话的播放状态和元数据。这就是锁定屏幕如何显示媒体控件和插图的方式。行为因 Android 版本而异。

专辑插图

在 Android 4.0(API 级别 14)到 Android 10(API 级别 29)中,锁定屏幕的背景会显示您的专辑插图 - 但前提是媒体会话元数据包含背景位图。

传输控件

在 Android 4.0(API 级别 14)到 Android 4.4(API 级别 19)中,当媒体会话处于活动状态并且媒体会话元数据包含背景位图时,锁定屏幕会自动显示传输控件。

在 Android 5.0(API 级别 21)或更高版本中,系统不会在锁定屏幕上提供传输控件。相反,您应该使用 MediaStyle 通知 来显示传输控件。

添加自定义操作

媒体应用程序可以定义自定义操作;例如:竖起大拇指、喜欢或倒回 30 秒。自定义操作应实现全新的行为。不要使用自定义操作来替换 PlaybackStateCompat 中定义的标准传输控制操作之一。

使用 addCustomAction() 添加自定义操作。以下示例显示了如何为竖起大拇指操作添加控件

Kotlin

stateBuilder.addCustomAction(
        PlaybackStateCompat.CustomAction.Builder(
                CUSTOM_ACTION_THUMBS_UP,
                resources.getString(R.string.thumbs_up),
                thumbsUpIcon
        ).run {
            setExtras(customActionExtras)
            build()
        }
)

Java

stateBuilder.addCustomAction(new PlaybackStateCompat.CustomAction.Builder(
    CUSTOM_ACTION_THUMBS_UP, resources.getString(R.string.thumbs_up), thumbsUpIcon)
    .setExtras(customActionExtras)
    .build());

有关完整示例,请参阅 通用音乐播放器

您可以使用 onCustomAction() 响应操作。

Kotlin

override fun onCustomAction(action: String, extras: Bundle?) {
    when(action) {
        CUSTOM_ACTION_THUMBS_UP -> {
            ...
        }
    }
}

Java

@Override
public void onCustomAction(@NonNull String action, Bundle extras) {
    if (CUSTOM_ACTION_THUMBS_UP.equals(action)) {
        ...
    }
}

另请参阅 通用音乐播放器

媒体会话回调

主要的媒体会话回调方法是 onPlay()onPause()onStop()。您在此添加控制播放器的代码。

由于您在运行时(在 onCreate() 中)实例化并设置会话的回调,因此您的应用可以定义使用不同播放器的替代回调,并根据设备和/或系统级别选择合适的回调/播放器组合。您可以在不更改应用其余部分的情况下更改播放器。例如,您可以在 Android 4.1(API 级别 16)或更高版本上使用 ExoPlayer,并在早期系统上使用 MediaPlayer

除了控制播放器和管理媒体会话状态转换之外,回调还启用和禁用应用的功能并控制它与其他应用和设备硬件的交互方式。(请参阅 控制音频输出)。

媒体会话回调方法的实现取决于应用的结构。请参阅单独的页面,这些页面描述了如何在音频应用视频应用中使用回调,并说明了每种类型的应用应如何实现回调。