处理音频输出变化
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
用户希望能够控制音频应用的音量。标准行为包括能够使用音量控件(设备上的按钮或旋钮,或界面中的滑块),并避免在使用过程中耳机等外围设备断开连接时突然大声播放。
使用音量控件
当用户按下游戏或音乐应用中的音量键时,即使播放器在歌曲之间暂停或当前游戏位置没有音乐,音量也应该发生变化。
Android 为音乐播放、闹钟、通知、来电铃声、系统提示音、通话音量和 DTMF 音使用单独的音频流。这样,用户就可以独立控制每个音频流的音量。
默认情况下,按音量控件可调节活动音频流的音量。如果您的应用当前未播放任何内容,按音量键可调节音乐音量(Android 9 之前调节的是铃声音量)。
除非您的应用是闹钟,否则您应播放使用情况为 AudioAttributes.USAGE_MEDIA
的音频。
为了确保音量控件能够调节正确音频流的音量,您应该调用 setVolumeControlStream()
,并传递与您可以从 AudioAttributes.getVolumeControlStream
检索的属性相匹配的音频流类型。
Kotlin
setVolumeControlStream(AudioManager.STREAM_MUSIC)
Java
setVolumeControlStream(AudioManager.STREAM_MUSIC);
在应用生命周期中进行此调用,通常是从控制媒体的 activity 或 fragment 的 onResume()
方法中调用。每当目标 activity 或 fragment 可见时,此调用即会将音量控件连接到 STREAM_MUSIC
。
以编程方式控制音频流音量
在极少数情况下,您可以通过编程方式设置音频流的音量。例如,当您的应用替换了现有界面时。建议不要这样做,因为 Android AudioManager
会将所有相同类型的音频流混合在一起。以下方法会改变使用该音频流的每个应用的音量。请避免使用以下内容:
使用固定音量设备
部分设备(如 Chromebook 和 Android Automotive OS 汽车)具有音量控件,但不允许应用使用上述 AudioManager
方法来更改音频流的音量。这些设备称为固定音量设备。您可以调用 isVolumeFixed()
,了解自己的应用是否在固定容量设备上运行。
音频应用应能够将其输出音量与可能在同一音频流上播放的其他应用进行平衡。在固定音量设备上,应用应将自己的音量控件连接到相应的 setVolume()
方法:
不要发出噪音
用户在 Android 设备上欣赏音频时,有多种选择。大多数设备都配有内置扬声器、有线耳机耳机插孔,很多设备还配备蓝牙连接并支持 A2DP 音频。
当耳机被拔下或蓝牙设备断开连接时,音频流会自动重新传送至内置扬声器。如果您以高音量聆听音乐,这时可能发出让人无法忍受的噪音。
在这种情况下,用户通常希望应用包含的音乐播放器具有屏幕播放控件来暂停播放。其他应用(例如不含控件的游戏)应继续播放。用户可以使用设备的硬件控件调整音量。
当音频输出切回到内置扬声器时,系统会广播 ACTION_AUDIO_BECOMING_NOISY
intent。您应该创建一个 BroadcastReceiver
,用于在每次播放音频时监听此 intent。您的接收器应如下所示:
Kotlin
private class BecomingNoisyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == AudioManager.ACTION_AUDIO_BECOMING_NOISY) {
// Pause the playback
}
}
}
Java
private class BecomingNoisyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
// Pause the playback
}
}
}
在开始播放时注册接收器,并在停止时取消注册接收器。如果按照本指南的说明设计应用,这些调用应显示在 onPlay()
和 onStop()
媒体会话回调中。
Kotlin
private val intentFilter = IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY)
private val myNoisyAudioStreamReceiver = BecomingNoisyReceiver()
private val callback = object : MediaSessionCompat.Callback() {
override fun onPlay() {
registerReceiver(myNoisyAudioStreamReceiver, intentFilter)
}
override fun onStop() {
unregisterReceiver(myNoisyAudioStreamReceiver)
}
}
Java
private IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
private BecomingNoisyReceiver myNoisyAudioStreamReceiver = new BecomingNoisyReceiver();
MediaSessionCompat.Callback callback = new
MediaSessionCompat.Callback() {
@Override
public void onPlay() {
registerReceiver(myNoisyAudioStreamReceiver, intentFilter);
}
@Override
public void onStop() {
unregisterReceiver(myNoisyAudioStreamReceiver);
}
}
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-07-27。
[null,null,["最后更新时间 (UTC):2025-07-27。"],[],[],null,["# Handling changes in audio output\n\nUsers expect to be able to control the volume of an audio app. Standard behavior\nincludes the ability to use the volume controls (either buttons or knobs on the\ndevice or sliders in the UI), and to avoid suddenly playing out loud if a\nperipheral like headphones is disconnected while in use.\n\nUsing the volume controls\n-------------------------\n\nWhen a user presses a volume key in a game or music app the volume should\nchange, even if the player is paused between songs or there's no music for the\ncurrent game location.\n\nAndroid uses separate audio streams for playing music, alarms,\nnotifications, the incoming call ringer, system sounds, in-call volume, and DTMF\ntones. This allows users to control the volume of each stream independently.\n\nBy default, pressing the volume control modifies the volume of the active audio\nstream. If your app isn't currently playing anything, hitting the volume keys\nadjusts the music volume (or the ringer volume before Android 9).\n\nUnless your app is an alarm clock, you should play audio with usage\n[AudioAttributes.USAGE_MEDIA](/reference/android/media/AudioAttributes#USAGE_MEDIA).\n\nTo ensure that volume controls adjust\nthe correct stream, you should call\n[setVolumeControlStream()](/reference/android/app/Activity#setVolumeControlStream(int))\npassing in the stream type matching your attributes that you can retrieve from\n[AudioAttributes.getVolumeControlStream](/reference/android/media/AudioAttributes#getVolumeControlStream()). \n\n### Kotlin\n\n```kotlin\nsetVolumeControlStream(AudioManager.STREAM_MUSIC)\n```\n\n### Java\n\n```java\nsetVolumeControlStream(AudioManager.STREAM_MUSIC);\n```\n\nMake this call in your app's lifecycle, typically from the `onResume()`\nmethod of the activity or fragment that controls your media. This connects\nthe volume controls to `STREAM_MUSIC` whenever the target activity or fragment\nis visible.\n\n### Controlling stream volume programmatically\n\nIn rare cases, you can set the volume of an audio stream programmatically. For\nexample, when your app replaces an existing UI. This is not recommended because\nthe Android `AudioManager` mixes all audio streams of the same type together.\nThese methods change the volume of every app that uses the stream. Avoid using\nthem:\n\n- [adjustStreamVolume()](/reference/android/media/AudioManager#adjustStreamVolume(int, int, int))\n- [adjustSuggestedStreamVolume()](/reference/android/media/AudioManager#adjustSuggestedStreamVolume(int, int, int))\n- [adjustVolume()](/reference/android/media/AudioManager#adjustVolume(int, int))\n- [setStreamVolume()\n setStreamVolume()](/reference/android/media/AudioManager#setStreamVolume(int, int, int))\n- [setStreamSolo()](/reference/android/media/AudioManager#setStreamSolo(int, boolean))\n- [setStreamMute()](/reference/android/media/AudioManager#setStreamMute(int, boolean))\n\nWorking with fixed-volume devices\n---------------------------------\n\nSome devices (like Chromebooks and Android Automotive OS cars) have volume\ncontrols but don't allow apps to use the `AudioManager` methods described\nearlier to change the level of an audio stream. These are called *fixed-volume*\ndevices. You can discover if your app is running on a fixed-volume device by\ncalling [`isVolumeFixed()`](/reference/android/media/AudioManager#isVolumeFixed()).\n\nAn audio app should provide the ability to balance\nits output volume with other apps that might be playing on the same stream.\nOn *fixed-volume* devices, the app should connect its own volume controls to the\nappropriate `setVolume()` method:\n\n| Player | Method |\n|-------------|---------------------------------------------------------------------------------------------------------------------------------|\n| AudioTrack | [AudioTrack.setVolume()](/reference/android/media/AudioTrack#setVolume(float)) |\n| MediaPlayer | [MediaPlayer.setVolume()](/reference/android/media/MediaPlayer#setVolume(float, float)) |\n| ExoPlayer | Use `SimpleExoPlayer.setVolume()` which sets the volume of the underlying AudioTrack. |\n| Web | Set the [`volume`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/volume) property of the `HTMLMediaElement` |\n\nDon't be noisy\n--------------\n\nUsers have a number of alternatives when it comes to enjoying the audio from\ntheir Android devices. Most devices have a built-in speaker, headphone jacks for\nwired headsets, and many also feature Bluetooth connectivity and support for\nA2DP audio.\n\nWhen a headset is unplugged or a Bluetooth device disconnected, the audio stream\nautomatically reroutes to the built-in speaker. If you listen to music at a high\nvolume, this can be a noisy surprise.\n\nUsers usually expect apps that include a music player with onscreen playback\ncontrols to pause playback in this case. Other apps, like games that don't\ninclude controls, should keep playing. The user can adjust the volume with the\ndevice's hardware controls.\n\nWhen audio output switches back to the built-in speaker the system broadcasts an [ACTION_AUDIO_BECOMING_NOISY](/reference/android/media/AudioManager#ACTION_AUDIO_BECOMING_NOISY)\nintent. You should create a [BroadcastReceiver](/reference/android/content/BroadcastReceiver)\nthat listens for this intent whenever you're playing audio. Your receiver should look like this: \n\n### Kotlin\n\n```kotlin\nprivate class BecomingNoisyReceiver : BroadcastReceiver() {\n\n override fun onReceive(context: Context, intent: Intent) {\n if (intent.action == AudioManager.ACTION_AUDIO_BECOMING_NOISY) {\n // Pause the playback\n }\n }\n}\n```\n\n### Java\n\n```java\nprivate class BecomingNoisyReceiver extends BroadcastReceiver {\n @Override\n public void onReceive(Context context, Intent intent) {\n if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {\n // Pause the playback\n }\n }\n}\n```\n\nRegister the receiver when you begin playback, and unregister it when you stop.\nIf you design your app as we describe in this guide, these calls should appear\nin the `onPlay()` and `onStop()` media session callbacks. \n\n### Kotlin\n\n```kotlin\nprivate val intentFilter = IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY)\nprivate val myNoisyAudioStreamReceiver = BecomingNoisyReceiver()\n\nprivate val callback = object : MediaSessionCompat.Callback() {\n\n override fun onPlay() {\n registerReceiver(myNoisyAudioStreamReceiver, intentFilter)\n }\n\n override fun onStop() {\n unregisterReceiver(myNoisyAudioStreamReceiver)\n }\n}\n```\n\n### Java\n\n```java\nprivate IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);\nprivate BecomingNoisyReceiver myNoisyAudioStreamReceiver = new BecomingNoisyReceiver();\n\nMediaSessionCompat.Callback callback = new\nMediaSessionCompat.Callback() {\n @Override\n public void onPlay() {\n registerReceiver(myNoisyAudioStreamReceiver, intentFilter);\n }\n\n @Override\n public void onStop() {\n unregisterReceiver(myNoisyAudioStreamReceiver);\n }\n}\n```"]]