让我们把Android音频焦点系统想象成一场“音乐酒吧的抢麦大战”,而你的AppB(音乐播放器)就是酒吧里的驻唱歌手🎤。当不同类型的“抢麦者”(AppA)冲上台时,系统只会对歌手喊一句“台下休息!”(AUDIOFOCUS_LOSS_TRANSIENT)。歌手如何知道该“暂停唱歌”(暂停播放)还是“立刻闭嘴”(立即静音)?下面用故事+技术拆解这个难题👇
🎭 故事场景:相同的指令,不同的危机
- 普通顾客抢麦(AppA:
AUDIOFOCUS_GAIN_TRANSIENT)
→ 一位醉汉冲上台喊:“生日快乐!”(短暂提示音)
→ 系统对歌手喊:“台下休息!”
→ 歌手行为:放下麦克风⏸️,记住歌词位置(暂停播放),等醉汉说完再接着唱。 - 紧急广播员抢麦(AppA:
AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
→ 消防员冲进来喊:“火灾警报!所有人撤离!”(电话/录音)
→ 系统同样喊:“台下休息!”
→ 歌手行为:瞬间闭嘴🤐(立即静音),但手仍握着麦克风(不释放资源),等警报结束再恢复。
🔍 问题核心:相同的回调,如何区分?
系统只发AUDIOFOCUS_LOSS_TRANSIENT,但危机级别不同!解决方案是:
✅ 方法1:查看“抢麦者身份证”(Android 8.0+)
通过AudioManager.getAudioFocusInfo()获取当前焦点持有者的音频属性(AudioAttributes),判断对方身份:
java
Copy
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AudioFocusInfo focusInfo = audioManager.getAudioFocusInfo();
AudioAttributes attrs = focusInfo.getAttributes();
// 场景1:对方是电话/录音(必须静音)
if (attrs.getUsage() == AudioAttributes.USAGE_VOICE_COMMUNICATION) {
muteImmediately(); // 立即静音!🤐
}
// 场景2:对方是普通提示音(暂停即可)
else {
pausePlayback(); // 暂停⏸️
}
}
}
}
技术原理:电话/录音的
AudioAttributes会标记为USAGE_VOICE_COMMUNICATION,而提示音通常是USAGE_NOTIFICATION。
✅ 方法2:监听“酒吧大环境”(兼容旧版Android)
若手机版本<Android 8.0,可通过系统状态间接判断:
java
Copy
private void handleTransientLoss() {
// 检查系统是否正在通话
if (audioManager.getMode() == AudioManager.MODE_IN_CALL) {
muteImmediately(); // 静音!
}
// 检查是否正在录音(需权限)
else if (isSystemRecordingActive()) {
muteImmediately();
}
else {
pausePlayback(); // 普通暂停
}
}
避坑:静音时用
setVolume(0f),暂停时用pause()+记录播放位置 。
⚙️ 实战增强:歌手生存指南
| 场景 | 判断依据 | 行动 | 恢复动作 |
|---|---|---|---|
| 电话/录音抢麦 | AudioAttributes.USAGE_VOICE_COMMUNICATION | 立即静音 (setVolume(0)) | 音量恢复 (setVolume(1)) |
| 导航/提示音抢麦 | AudioAttributes.USAGE_NOTIFICATION | 暂停播放 (pause()) | 从暂停位置继续 (resume()) |
| 未知抢麦者(兼容模式) | 系统通话状态/录音权限检测 | 静音(安全策略) | 根据场景恢复 |
🚨 关键陷阱:别让歌手“假死”
-
静音≠暂停:静音后需监听
AUDIOFOCUS_GAIN回调恢复音量,但不要自动播放(用户可能已离开) 。 -
资源释放:仅在收到
AUDIOFOCUS_LOSS(永久丢失)时才释放MediaPlayer! -
Android 12+特权:系统会强制淡出非语音应用,但仍需处理回调(防止厂商兼容问题) 。
💡 一句话总结
当歌手听到“台下休息”(
AUDIOFOCUS_LOSS_TRANSIENT)时,先看抢麦者是谁(查AudioAttributes),再看现场是否在救火(查通话/录音状态)。普通醉汉→暂停,消防员→闭嘴,完事儿后乖乖等系统喊“上台继续唱”(AUDIOFOCUS_GAIN)!
通过这种策略,你的AppB就能在“抢麦大战”中优雅生存,既遵守系统规则,又保证用户体验🎶。 (技术细节参考Android AudioFocusRequest设计文档)