本文譯自:http://developer.android.com/training/managing-audio/audio-focus.html
考慮如何跟多個潛在的音頻播放程式互動是至關重要的。要避免每個音樂播放器同時播放,Android使用音頻焦點(Audio Focus)來控制音頻播放---只有擁有音頻焦點的應用程式才能播放音頻。
在你的應用程式開始播放音頻之前,它應該請求、接收音頻焦點。而且,它還應該知道如何監聽音頻焦點的丟失,以及在音頻焦點丟失時,如何做出正確的響應。
請求音頻焦點
在應用程式開始播放任何音頻之前,它應該擁有它將使用的音頻流的音頻焦點。通過調用requestAudioFocus()方法來擷取音頻焦點,如果請求成功,該方法會返回AUDIOFOCUS_REQUEST_GRANTED。
你必須指定你所要使用的音頻流,以及要求的音頻焦點時臨時性還是持久性的。當你期望只播放很短的音頻是,可請求臨時音頻焦點(例如播放導航說明的時候)。在播放具有預見性的音頻時,可請求持久性的音頻焦點(例如,播放音樂的時候)。
下面的程式碼片段在音樂音頻流上請求了持久性的音頻焦點。在開始播放之前,你應該立即請求音頻焦點,如使用者按下播放按鈕的時候或下個遊戲層級的背景音樂開始之前。
AudioManager am
= mContext.getSystemService(Context.AUDIO_SERVICE);
...
// Request audio focus for playback
int result = am.requestAudioFocus(afChangeListener,
// Use the music stream.
AudioManager.STREAM_MUSIC,
// Request permanent focus.
AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
// Start playback.
}
完成播放後,一定要確保調用abandonAudioFocus()方法。這個方法會通知系統你不再需要音頻焦點了,並且會解除與AudioManager.OnAudioFocusChangeListener關聯的註冊。放棄臨時性音頻焦點的情況下,就會允許任何被中斷的應用應用程式繼續播放。
// Abandon audio focus when playback complete
am.abandonAudioFocus(afChangeListener);
在請求臨時性的音頻焦點時會有另外一個選項:是否啟用“迴避”。通常,良好的音頻應用程式在丟失音頻焦點時立即關閉它的播放。通過請求臨時性的允許迴避的音頻焦點,會告訴其他可訪問的音頻應用程式保持播放狀態,但他們的音量會被降低,直到音頻焦點返回給它們。
// Request audio focus for playback
int result = am.requestAudioFocus(afChangeListener,
// Use the music stream.
AudioManager.STREAM_MUSIC,
// Request permanent focus.
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// Start playback.
}
“迴避”特別適用於那些間歇性適用音頻流的應用程式,如語音駕駛導航。
無論應用程式什麼時候請求上述介紹的那種類型的音頻焦點,都是通過註冊監聽器來接收持久性或臨時性的音頻焦點(不管支不支援迴避)。
處理音頻焦點的丟失
如果你的應用程式可以請求音頻焦點,那麼在另一個應用程式請求該焦點時,它又會丟失焦點。你的應用程式如何響應音頻焦點的丟失依賴與對丟失焦點的管理。
你註冊的音頻焦點變化監聽器的onAudioFocusChange()回調方法會接收一個描述焦點變化事件的參數。具體來說,可能的焦點丟失事件會對應到前面提到的請求焦點的類型---持久性丟失、臨時性丟失,以及帶有允許迴避的臨時性丟失。
一般來說,音頻焦點的臨時性丟失會導致你的應用程式讓它的音頻流保持沉默狀態,但在其他方面卻保持相同的狀態。你應該繼續監視音頻焦點的變化,並準備在重新擷取焦點時恢複被暫停音頻流播放。
如果丟失的音頻焦點是持久性的,那麼它會假設正在使用另一個應用程式來聽音頻,並且你應用程式應該被有效結束。在實際的應用中,這意味著停止播放、刪除媒體按鈕監聽器---允許新的音頻播放器來專門處理這些事件---並且放棄你的音頻焦點。這時在恢複播放音頻之前,你會期望使用者執行必要的操作(如按下應用中的播放按鈕)。
在下面的程式碼片段中,如果丟失的是臨時性的音頻焦點,我們會暫停播放或媒體播放器對象,並且會在重新擷取焦點時再恢複它。如果丟失的是持久性的音頻焦點,它會解除我們的媒體按鈕事件接收的註冊,並且停止對音頻焦點變化的監聽。
OnAudioFocusChangeListener afChangeListener
=newOnAudioFocusChangeListener(){
public void onAudioFocusChange(int focusChange) {
if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT
// Pause playback
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Resume playback
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
am.abandonAudioFocus(afChangeListener);
// Stop playback
}
}
};
在音頻焦點臨時性丟失,且允許迴避的情況下,你可以用“迴避”來代替暫停播放。
迴避
迴避是一種降低你的臨時性音頻流輸出音量的處理,從而讓另一個應用程式的音頻更容易聽到,而不至於與你的應用程式的音頻流混淆。
下面的程式碼片段會在臨時性丟失焦點時降低媒體播放對象的音量,然後在重新擷取焦點時在返回到之前的層級。
OnAudioFocusChangeListener afChangeListener
=newOnAudioFocusChangeListener(){
public void onAudioFocusChange(int focusChange) {
if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
// Lower the volume
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Raise it back to normal
}
}
};
音頻焦點的丟失時最重要的廣播,但卻不是唯一的。系統會廣播很多Intent來提醒你改變使用者的音頻體驗。下節課會示範如何監視這些廣播來改善使用者的整體體驗。