🚨 核心矛盾:相同的回调(AUDIOFOCUS_LOSS_TRANSIENT)却需不同响应
💡 专业解决方案:AppB必须通过双重判断机制识别真实场景!
🧠 专业级处理方案(四步破解)
1️⃣ 第一步:统一暂停(基础响应)
java
// 收到任何 AUDIOFOCUS_LOSS_TRANSIENT 先暂停
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
mediaPlayer.pause(); // 所有场景先暂停
startEmergencyCheck(); // 启动紧急静音检测
}
}
2️⃣ 第二步:检测系统级静音(独家秘笈)
java
// 监听系统强制静音信号(Android 8.0+)
private void startEmergencyCheck() {
new Handler().postDelayed(() -> {
// 关键检测:系统是否强制静音了音频流
if (audioManager.isStreamMute(AudioManager.STREAM_MUSIC)) {
activateEmergencyMute(); // 紧急静音模式
} else {
normalPauseMode(); // 普通暂停模式
}
}, 150); // 延迟150ms等待系统响应
}
⚠️ 原理:系统处理
TRANSIENT_EXCLUSIVE时会强制静音音频流,而普通TRANSIENT不会
3️⃣ 第三步:分场景精细化处理
java
// 场景1:普通短暂打断(如导航提示)
private void normalPauseMode() {
keepBuffering(); // 保持缓冲
showPauseIcon(); // 显示暂停图标
// 等待焦点返回自动恢复
}
// 场景2:VIP独占打断(如电话接通)
private void activateEmergencyMute() {
mediaPlayer.setVolume(0, 0); // 双重静音
releaseDecoderResources(); // 释放解码器资源
showInterruptedBadge(); // 显示"被电话打断"提示
}
4️⃣ 第四步:焦点恢复时的差异处理
java
case AudioManager.AUDIOFOCUS_GAIN:
if (isEmergencyMuted) {
reinitializePlayer(); // 独占打断需重新初始化播放器
} else {
mediaPlayer.start(); // 普通暂停直接恢复
}
break;
🔍 深度技术解析(为什么必须这样做?)
| 判断维度 | TRANSIENT | TRANSIENT_EXCLUSIVE |
|---|---|---|
| 系统行为 | 仅发送回调 | 发送回调+强制静音音频流 |
| 音频流状态 | 仍可播放(但应暂停) | 被系统设为静音 |
| 恢复成本 | 低(直接播放) | 高(可能需重新初始化) |
| 用户感知 | 音乐暂停但设备未静音 | 整个设备突然静音 |
🛠️ 终极代码方案(兼容Android 5.0+)
java
public class SmartAudioPlayer implements AudioManager.OnAudioFocusChangeListener {
private boolean isExclusiveInterrupt;
@Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
handleTransientLoss();
break;
// 其他case...
}
}
private void handleTransientLoss() {
// 先统一暂停
mediaPlayer.pause();
// 延迟检测静音状态
new Handler().postDelayed(() -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 现代系统检测API
isExclusiveInterrupt = audioManager.isStreamMute(AudioManager.STREAM_MUSIC);
} else {
// 传统系统通过音量检测
int vol = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
isExclusiveInterrupt = (vol == 0);
}
if (isExclusiveInterrupt) {
onExclusiveInterrupt();
}
}, 150); // 经验值延迟
}
private void onExclusiveInterrupt() {
// 1. 保存播放状态
savePlaybackState();
// 2. 释放关键资源
mediaPlayer.release();
// 3. 监听系统静音解除
registerMuteMonitor();
}
// 监听系统静音状态变化
private void registerMuteMonitor() {
audioManager.registerAudioDeviceCallback(new AudioDeviceCallback() {
@Override
public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
checkAudioUnmute();
}
}, null);
}
private void checkAudioUnmute() {
if (!audioManager.isStreamMute(AudioManager.STREAM_MUSIC)) {
restorePlayback(); // 系统解除静音后恢复
}
}
}
💎 顶级专家建议
-
延迟检测值:150ms是经验值(覆盖系统处理延迟),可实测调整
-
双保险策略:
java
// 在onExclusiveInterrupt()中增加: mediaPlayer.setVolume(0, 0); // 应用层静音 audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_MUTE, 0); // 同步系统层 -
Android 13+ 优化:使用
AudioFocusRequest.Builder.setAcceptsDelayedFocusGain()处理复杂场景 -
设备兼容性:华为/小米等定制ROM需单独测试静音API
🌟 精髓总结:相同的回调只是战争的开始,需要通过监听系统状态+延迟探测识别战场真相。就像急诊医生看到病人昏迷,会立即查瞳孔反射判断是普通晕厥还是脑死亡!