處理音訊輸出的變化
透過集合功能整理內容
你可以依據偏好儲存及分類內容。
使用者預期能夠控制音訊應用程式的音量。標準行為包括使用音量控制選項 (裝置上的按鈕或旋鈕,或 UI 中的滑桿),以及避免在使用時,耳機等周邊裝置突然斷開連線而突然播放出聲。
使用音量控制
當使用者在遊戲或音樂應用程式中按下音量鍵時,音量應會變更,即使播放器在歌曲之間暫停,或是目前遊戲位置沒有音樂,也一樣。
Android 會使用不同的音訊串流播放音樂、鬧鐘、通知、來電鈴聲、系統音效、通話音量和 DTMF 音效。這樣一來,使用者就能個別控制各個串流的音量。
根據預設,按下音量控制鍵會修改有效音訊串流的音量。如果應用程式目前沒有播放任何內容,按下音量鍵會調整音樂音量 (或在 Android 9 之前調整鈴聲音量)。
除非您的應用程式是鬧鐘,否則應使用 AudioAttributes.USAGE_MEDIA
播放音訊。
為確保音量控制項調整正確的串流,您應呼叫 setVolumeControlStream()
,並傳入與您從 AudioAttributes.getVolumeControlStream
擷取的屬性相符的串流類型。
Kotlin
setVolumeControlStream(AudioManager.STREAM_MUSIC)
Java
setVolumeControlStream(AudioManager.STREAM_MUSIC);
請在應用程式的生命週期中發出這個呼叫,通常是從控制媒體的活動或片段的 onResume()
方法中發出。這樣一來,只要目標活動或片段可見,系統就會將音量控制項連結至 STREAM_MUSIC
。
以程式輔助的方式控制串流音量
在極少數情況下,您可以透過程式設定音訊串流的音量。例如,當應用程式取代現有的 UI 時。我們不建議這麼做,因為 Android AudioManager
會將所有相同類型的音訊串流混合在一起。這些方法會變更使用串流的每個應用程式音量。請避免使用以下字詞:
使用固定音量裝置
部分裝置 (例如 Chromebook 和 Android Automotive OS 汽車) 具有音量控制選項,但不允許應用程式使用前述的 AudioManager
方法來變更音訊串流的音量。這類裝置稱為固定音量裝置。您可以呼叫 isVolumeFixed()
,瞭解應用程式是否在固定音量的裝置上執行。
音訊應用程式應提供平衡功能,讓使用者調整輸出音量,以便與可能在同一串流中播放的其他應用程式保持平衡。在固定音量裝置上,應用程式應將其自身的音量控制項連結至適當的 setVolume()
方法:
請勿製造噪音
使用者可以透過多種方式,透過 Android 裝置享受音訊。大多數裝置都內建喇叭,並提供可連接有線耳機的耳機插孔,許多裝置也支援藍牙連線和 A2DP 音訊。
當耳機拔除或藍牙裝置連線中斷時,音訊串流會自動重新導向至內建喇叭。如果你以高音量聆聽音樂,可能會聽到噪音。
在這種情況下,使用者通常會預期應用程式會暫停播放音樂,並提供螢幕上的播放控制項。其他應用程式 (例如不含控制項的遊戲) 應可繼續播放。使用者可以使用裝置的硬體控制項調整音量。
當音訊輸出切換回內建喇叭時,系統會廣播 ACTION_AUDIO_BECOMING_NOISY
意圖。您應建立 BroadcastReceiver
,在播放音訊時監聽此意圖。接收器應如下所示:
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 和/或其關係企業的商標或註冊商標。
上次更新時間:2025-07-27 (世界標準時間)。
[[["容易理解","easyToUnderstand","thumb-up"],["確實解決了我的問題","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["缺少我需要的資訊","missingTheInformationINeed","thumb-down"],["過於複雜/步驟過多","tooComplicatedTooManySteps","thumb-down"],["過時","outOfDate","thumb-down"],["翻譯問題","translationIssue","thumb-down"],["示例/程式碼問題","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["上次更新時間: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```"]]