如何实现其他应用播放音频时停止ExoPlayer电台流播放?
嘿,这个需求其实在Android音频生态里是靠**音频焦点(Audio Focus)**来实现的,ExoPlayer本身已经封装了相关能力,不用你自己从零监听所有事件,下面一步步给你拆解:
核心方案:利用Android音频焦点机制
Android系统通过音频焦点来协调多个应用的音频播放——当一个应用要播放音频时,需要先向系统请求焦点;当其他应用请求焦点时,当前持有焦点的应用会收到通知,这时候咱们就可以暂停自己的电台流。
1. 最省心:用ExoPlayer自动处理音频焦点
ExoPlayer内置了音频焦点的管理逻辑,你只需要配置好播放器的音频属性,让它自动接管焦点处理就行:
// 配置你的电台流对应的音频属性 val audioAttributes = AudioAttributes.Builder() .setContentType(C.CONTENT_TYPE_MUSIC) // 电台流属于音乐类内容 .setUsage(C.USAGE_MEDIA) .build() // 给播放器设置音频属性,第二个参数设为true,让播放器自动处理焦点 player.setAudioAttributes(audioAttributes, true)
这样设置后,当其他应用(比如音乐APP、通话)抢占音频焦点时,ExoPlayer会自动暂停播放;当焦点重新回到你的应用时,还能自动恢复播放(这个逻辑可以通过播放器的参数微调)。
2. 自定义处理:手动监听焦点变化
如果默认的自动逻辑不够满足你的需求(比如想在暂停时显示提示、做额外的UI操作),可以手动设置焦点回调,精细控制每个场景的行为:
// 先创建音频焦点请求对象 val audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) .setAudioAttributes(audioAttributes) .setOnAudioFocusChangeListener { focusChange -> when (focusChange) { AudioManager.AUDIOFOCUS_LOSS -> { // 永久失去焦点(比如用户打开了另一个音乐APP),直接停止播放 player.stop() } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { // 暂时失去焦点(比如来电、微信语音通话),暂停播放 player.pause() } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { // 暂时失去焦点,但可以降低音量继续播放(比如导航播报) player.volume = 0.3f } AudioManager.AUDIOFOCUS_GAIN -> { // 重新获得焦点,恢复播放和正常音量 player.play() player.volume = 1.0f } } } .build() // 手动向系统请求音频焦点 val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager val result = audioManager.requestAudioFocus(audioFocusRequest) if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { player.play() }
这种方式需要你自己管理焦点的请求和释放,适合有特殊业务逻辑的场景。
3. 可选补充:监听通话状态
其实音频焦点机制已经能覆盖来电/通话的场景,但如果你需要更直接地监听通话状态,可以注册TelephonyManager的监听:
val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager telephonyManager.listen(object : PhoneStateListener() { override fun onCallStateChanged(state: Int, phoneNumber: String?) { super.onCallStateChanged(state, phoneNumber) when (state) { // 来电响铃或正在通话时,暂停播放 TelephonyManager.CALL_STATE_RINGING, TelephonyManager.CALL_STATE_OFFHOOK -> { if (player.isPlaying) player.pause() } // 通话结束后,恢复播放(根据你的需求调整) TelephonyManager.CALL_STATE_IDLE -> { player.play() } } } }, PhoneStateListener.LISTEN_CALL_STATE)
注意:Android 10及以上需要申请READ_PHONE_STATE权限,而且这个属于额外补充,一般情况下用音频焦点就足够了。
总结
- 优先用ExoPlayer自带的自动音频焦点处理,代码少、逻辑稳,能自动响应所有其他音频播放/来电场景;
- 有特殊需求时,再手动实现焦点回调来定制行为;
- 通话监听是可选操作,非必须。
内容的提问来源于stack exchange,提问作者Kostek




