翻译自: Responding to media buttons
媒体按钮是 Android 设备和其他外围设备上的硬件按钮, 例如蓝牙耳机上的暂停 / 播放按钮. 当用户按下媒体按钮时, Android 会生成一个, 其中包含一个识别按钮的密钥代码. media button KeyEvents 的关键代码是以 KEYCODE_MEDIA 开头的常量(例如, KEYCODE_MEDIA_PLAY).
应用程序应该能够在三种情况下处理媒体按钮事件, 按优先顺序排列:
当应用程序的 UI 活动可见时
当 UI 活动隐藏且应用程序的媒体会话处于活动状态时
当 UI 活动被隐藏, 应用程序的媒体会话不活跃, 需要重新启动时
处理前台活动中的媒体按钮
前台活动在其 onKeyDown()方法中接收 media button key 事件. 根据 Android 的运行版本, 系统有两种方式将事件路由到媒体控制器:
如果你运行的是安卓 5.0 (API level 21)或更高版本, 调用
MediaBrowserCompat.ConnectionCallback.onConnected
. 这将自动调用您的媒体控制器的 dispatchMediaButtonEvent(), 它将关键代码转换为媒体会话回调.
在 Android 5.0 (API level 21)之前, 您需要修改 onKeyDown()来自己处理事件.(有关详细信息, 请参阅 Handling media buttons in an active media session.)下面的代码片段展示了如何截获关键代码并调用 dispatchMediaButtonEvent(). 确保返回 true 以指示事件已处理:
- @Override
- boolean onKeyDown(int keyCode, KeyEvent event) {
- if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.LOLLIPOP) {
- return super.onKeyDown(keyCode, event);
- }
- switch (keyCode) {
- case KeyEvent.KEYCODE_MEDIA_PLAY:
- yourMediaController.dispatchMediaButtonEvent(event);
- return true;
- }
- return super.onKeyDown(keyCode, event);
- }
寻找媒体会话
如果前台活动不处理事件, Android 将尝试找到一个可以处理它的媒体会话. 同样, 根据 Android 的运行版本, 有两种方法可以搜索媒体会话:
如果你运行的是安卓 8.0 (API level 26)或更高版本, 系统会试图找到最后一个带有本地播放音频的 MediaSession 的应用. 如果会话仍然是活动的, Android 会将事件直接发送到它. 否则, 如果会话不是活动的, 并且它有一个 mediabutton 接收器, Android 将事件发送给接收器, 接收器将重新启动会话, 因此它可以接收事件.(有关详细信息, 请参阅 Using media buttons to restart an inactive media session .)如果会话没有媒体按钮接收器, 系统将丢弃媒体按钮事件, 并且什么也不会发生. 逻辑如下图所示:
在 Android 8.0 (API 级别 26)之前, 系统尝试将事件发送到活动媒体会话. 如果有多个活动媒体会话, Android 会尝试选择准备播放 (缓冲 / 连接), 播放或暂停的媒体会话, 而不是停止的.(有关更多细节, 请参见 Handling media buttons in an active media session.) 如果没有活动会话, Android 会尝试将事件发送到最近的活动会话.(有关详细信息, 请参阅使用 Using media buttons to restart an inactive media session.)逻辑如下图所示:
处理活动媒体会话中的媒体按钮
在 Android 5.0 (API level 21)及更高版本上, Android 通过调用 onMediaButtonEvent()自动将媒体按钮事件分派给您的活动媒体会话. 默认情况下, 此回调将 KeyEvent 转换为与密钥代码匹配的适当的媒体会话回调方法.
在 Android 5.0 (API level 21)之前, Android 通过使用 ACTION_MEDIA_BUTTON 操作广播一个意图来处理媒体按钮事件. 你的应用程序必须注册一个广播接收器来拦截这些意图. 类是专门为此目的设计的. 它是 Android media-compat 库中的一个方便类, 它处理 ACTION_MEDIA_BUTTON 并将传入的意图转换为适当的 MediaSessionCompat.Callback 方法调用.
MediaButtonReceiver 是一个短命的广播接收器. 它将传入的意图转发给管理媒体会话的服务. 如果你想在 Android 5.0 之前在系统中使用媒体按钮, 你必须在清单中包括 MediaButtonReceiver 和 MEDIA_BUTTON 意图过滤器.
- <receiver Android:name="android.support.v4.media.session.MediaButtonReceiver">
- <intent-filter>
- <action Android:name="android.intent.action.MEDIA_BUTTON" />
- </intent-filter>
- </receiver>
广播接收器将意图转发给您的服务. 要解析意图并生成对媒体会话的回调, 请在服务的 onStartCommand()中包含 MediaButtonReceiver.handleIntent()方法. 这将把关键代码转换为适当的会话回调方法.
- private MediaSessionCompat mMediaSessionCompat = ...;
- public int onStartCommand(Intent intent, int flags, int startId) {
- MediaButtonReceiver.handleIntent(mMediaSessionCompat, intent);
- return super.onStartCommand(intent, flags, startId);
- }
注意: 如果您没有 MediaBrowserServiceCompat, 您还可以向任何服务添加 ACTION_MEDIA_BUTTON 意图过滤器. 有关更多信息, 请参阅文档.
使用媒体按钮重新启动非活动的媒体会话
如果 Android 能够识别最后一个活动媒体会话, 它会试图通过发送一个 ACTION_MEDIA_BUTTON 意图到一个声明注册的组件 (如服务或广播接收器) 来重新启动会话.
这可以让你的应用在 UI 不可见时重启回放, 这是大多数音频应用的情况.
当您使用 MediaSessionCompat 时, 将自动启用此行为. 如果你使用 Android 框架的 MediaSession 或者 Support Library 24.0.0 到 25.1.1, 你必须调用 setMediaButtonReceiver, 让媒体按钮重新启动一个非活动的媒体会话.
你可以通过设置一个空媒体按钮接收器, 在 Android 5.0 (API 级别 21)或更高版本中禁用此行为:
- // Create a MediaSessionCompat
- mMediaSession = new MediaSessionCompat(context, LOG_TAG);
- mMediaSession.setMediaButtonReceiver(null);
注意: 对于在 Android 5.0 (API level 21)之前的系统中运行的应用程序, 您注册以处理活动会话的媒体按钮的 MediaButtonReceiver 也会在会话不活动时接收媒体按钮事件. 无法禁用此行为.
定制媒体按钮处理程序
onMediaButtonEvent()的默认行为提取关键代码并使用媒体会话的当前状态和支持的操作列表来确定调用哪个方法. 例如, KEYCODE_MEDIA_PLAY 调用 onPlay().
为了在所有应用程序中提供一致的媒体按钮体验, 您应该使用默认行为, 并且只为了特定的目的而偏离. 如果媒体按钮需要自定义处理, 重写回调函数的 onMediaButtonEvent()方法, 使用 intent.getparcelableextra (Intent.EXTRA_KEY_EVENT)提取 KeyEvent, 自己处理事件, 并返回 true.
总结
要正确处理 Android 所有版本中的媒体按钮事件, 必须在创建媒体会话时指定.
此外, 根据您计划支持的 Android 版本, 您还必须满足以下要求:
运行 Android 5.0 或更高版本时:
从媒体控制器 onConnected()回调中调用
MediaControllerCompat.setMediaController()
要允许媒体按钮重新启动非活动会话, 可以通过调用
setMediaButtonReceiver()
并传递 PendingIntent 动态创建
MediaButtonReceiver
当系统运行时间早于 Android 5.0 时:
重写活动的 onKeyDown()以处理媒体按钮
静态创建一个
MediaButtonReceiver
通过添加它到应用程序的清单
来源: https://juejin.im/post/5bcdabc3f265da0ac37343f5