【Android】监听媒体按键按下--响应媒体按钮

媒体按钮是 Android 设备和其他外围设备上的硬件按钮,例如蓝牙耳机或者线控耳机上的暂停/播放按钮。当用户按下媒体按钮时,Android 会生成 KeyEvent,其中包含用于标识按钮的键码。

可先阅读一下官方的文档,了解下整个流程和机制:

官方文档:响应媒体按钮

本文是监听播放、上一首、下一首等按键事件的代码实现。

不同版本的实现方式,差异有点大,比较碎片化。本人肤浅地认为Android5.0以下通过广播的方式接收,5.0及以上通过MediaSession,官方也封装了MediaSessionCompat这个类,它里面做了5.0到目前最新Android版本的适配处理。

代码实现

引入androidx的suppor库:

implementation 'androidx.legacy:legacy-support-v4:1.0.0'

新建一个MediaButtonReceiver继承BroadcastReceiver:

class MediaButtonReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        val action = intent?.action ?: return
        when (action) {
            Intent.ACTION_MEDIA_BUTTON -> {
                val keyEvent =intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) as? KeyEvent ?: return
                when (keyEvent.action) {
                    KeyEvent.ACTION_DOWN -> {//按键按下
                        when (keyEvent.keyCode) {
                            KeyEvent.KEYCODE_MEDIA_PLAY->{//播放按钮
                                //处理你的逻辑
                            }
                            KeyEvent.KEYCODE_MEDIA_NEXT->{//下一首
                                //处理你的逻辑
                            }
                            KeyEvent.KEYCODE_MEDIA_PREVIOUS->{//上一首
                                //处理你的逻辑
                            }
                        }
                    }
                }

            }
        }

    }

}

在配置清单注册:

<receiver android:name=".receiver.MediaButtonReceiver">
    <intent-filter>
        <action android:name="android.intent.action.MEDIA_BUTTON" />
    </intent-filter>
</receiver>

ps:MEDIA_BUTTON这个action只支持静态注册的,别想着用动态注册了。

接下来:

private var mMediaPlayer: MediaPlayer? = null//用于抢占线控按键
private var mComponentName: ComponentName? = null
private var mMediaSession: MediaSessionCompat? = null

private fun registerMediaButtonReceiver() {
    val audioManager = getSystemService(AUDIO_SERVICE) as? AudioManager ?: return
    robKeyEvent()
    mComponentName = ComponentName(packageName, MediaButtonReceiver::class.java.name).apply {
        packageManager.setComponentEnabledSetting(
            this,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP
        )
        if (Build.VERSION.SDK_INT >= 21) {//5.0以上
            mMediaSession =
                MediaSessionCompat(this@MainActivity, "mbr", this, null).apply {
                    //指明支持的按键信息类型
                    setFlags(
                        MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or
                                MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
                    )

                    setCallback(object : MediaSessionCompat.Callback() {
                        override fun onMediaButtonEvent(mediaButtonEvent: Intent?): Boolean {
                            //通过Callback返回按键信息,为复用MediaButtonReceiver,直接调用它的onReceive()方法
                            MediaButtonReceiver().onReceive(this@MainActivity, mediaButtonEvent)
                            return true
                        }
                    }, Handler(Looper.getMainLooper()))

                    //把MediaSession置为active,这样才能开始接收各种信息
                    if (!isActive) {
                        isActive = true
                    }
                }

        } else {//5.0以下
            audioManager.registerMediaButtonEventReceiver(this)
        }
    }

}
    

private fun unRegisterMediaButtonReceiver() {
    val audioManager = getSystemService(AUDIO_SERVICE) as? AudioManager ?: return
    if (Build.VERSION.SDK_INT >= 21) {//5.0以上
        mMediaSession?.let {
            it.setCallback(null)
            it.release()
        }
    } else {//5.0以下
        mComponentName?.let {
            audioManager.unregisterMediaButtonEventReceiver(it)
        }

    }
}

private fun robKeyEvent() {
    if (mMediaPlayer == null) {
        mMediaPlayer = MediaPlayer.create(this, R.raw.audiofilename)//随便往raw文件夹放个小的音频文件进去
    }
    mMediaPlayer?.start()
    mMediaPlayer?.stop()
}
使用说明

界面onCreate时调用registerMediaButtonReceiver,onDestroy时调用unRegisterMediaButtonReceiver。

值得一提的是,MediaSession需要先抢占到音频焦点,才能起作用。

音频焦点系统一般都会给在最后播放过的MediaPlayer上,所以我们用了个MediaPlayer来抢占音频焦点。

更多关于音频焦点的研究,比如监听音频失焦、或者通过更优雅的方式来获取音频焦点等,请访问官方文档:

官方文档:管理音频焦点

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值