標籤:mediaplayer喚醒鎖音頻焦點
MediaPlayer的喚醒鎖
一般使用MediaPlayer播放音頻流,推薦使用一個Service來承載MediaPlayer,而不是直接在Activity裡使用。但是Android系統的功耗設計裡,為了節約電池消耗,如果裝置處於睡眠狀態,系統將試圖降低或者關閉一些沒裝置必須的特性,包括CUP和Wifi硬體,然後,如果是一個後台播放音樂的應用,降低CUP可能導致在後台啟動並執行時候幹擾音訊正常播放,關閉Wifi將可能導致網路音頻流的擷取出現錯誤。
為了確保MediaPlayer的承載的服務在系統睡眠的時候繼續正常運行下去,Android為我們提供了一種喚醒鎖(wake locks)的機制。它可以在系統睡眠的,依然保持鎖定硬體的正常工作。
確保在MediaPlayer啟動並執行時候,哪怕系統睡眠了CUP也能正常運行,需要使用MediaPlayer.setWakeMode()為MediaPlayer設定喚醒鎖。下面是setWakMode()的簽名:
setWakeMode(Context context, int mode)
第一個參數是當前上下文,第二個參數為需要加鎖的狀態,被設定為int類型的常量,定義在PowerManager這個final類中。PowerManager是專門用來管理Android功率消耗的鎖定狀態,與鎖定CUP相關的,有四種,分別設定CUP、螢幕、鍵盤等的各種保持喚醒的狀態,在這裡只需要設定為PARTIAL_WAKE_LOCK即可。
mediaPlayer = new MediaPlayer();// 設定CUP鎖定mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
一般對於鎖而言,鎖定了通常需要解鎖,但是這裡的喚醒說與MediaPlayer關聯,所以只需要在使用完之後release()釋放MediaPlayer即可,無需顯式的為其解鎖。在使用setWakeMode設定喚醒鎖的時候,還必須為應用賦予相應的許可權:
<uses-permission android:name="android.permission.WAKE_LOCK"/>
再來說說如何鎖定wifi硬體在系統睡眠的時候保持正常運行。wifi鎖通過WifiLock進行操作,而WifiLock通過WifiManager進行管理,通過WifiManager.createWifiLock()進行Wifi鎖定。
WifiManager.WifiLock createWifiLock(int lockType, String tag)
這個方法有多個重載,這裡介紹的這個,第一個參數設定鎖的狀態,為一個int類型的常量,定義在Context類中,這裡的應用情境一般設定為WIFI_MODE_FULL即可。第二個參數為WifiLock的標誌,用於確定wifiLock的。
wifiLock= ((WifiManager) getSystemService(this.WIFI_SERVICE)).createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");wifiLock.acquire();
當然,在應用中把Wifi鎖定之後,還需要在MediaPlayer.release()的時候為wifi硬體解鎖,為避免意外關閉的情況,最好在Android組件的onDestory()裡對其進行釋放,釋放Wifi鎖使用WifiLock.release()。
/*** 停止播放*/ protected void stop() {if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; // 釋放wifi鎖 wifiLock.release(); btn_play.setEnabled(true); Toast.makeText(this, "停止播放", 0).show(); } } @Override protected void onDestroy() { // 在activity結束的時候回收資源 if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; // 釋放wifi鎖 wifiLock.release(); } super.onDestroy(); }
MediaPlayer的音頻焦點
眾所周知,Android是一個多任務的作業系統,所以對於音訊播放,也許有幾個不同的媒體服務會同時播放,這樣可能導致一個比較雜亂的聲音環境,而錯過一些重要的聲音提醒。在Android2.2之後,Android提供了一種應用協商使用裝置音訊輸出的機制,這種機制稱為音頻焦點。
當應用程式需要輸出音頻或通知的時候,需要請求音頻焦點,當請求得到音頻焦點之後,監聽音頻焦點的變換,當音頻焦點變換了,根據返回回來的音頻焦點碼進行相應的處理。音頻焦點的註冊使用音頻管理器的AudioManager.requestAudioFocus()方法設定。它的簽名如下:
int requestAudioFocus(AudioManager.OnAudioFocusChangeListener l, int streamType, int durationHint)
這個方法的返回值是int類型,其含義被定義在AudioManager中以常量表示AUDIOFOCUS_REQUEST_FAILED(擷取音頻焦點成功)、AUDIOFOCUS_REQUEST_GRANTED(擷取音頻焦點失敗)。其中重要的是第一個參數,為音頻焦點變化的回呼函數,在其中可以設定如果音頻焦點變換了,當前應用如何管理MediaPlayer,第二個參數為媒體流的類型,第三個參數為持續的狀態。
AudioManager.OnAudioFocusChangeListener為音頻焦點變換的監聽器,其中需要實現一個方法:onAudioFocusChange(int focusChange)在音頻焦點變換的時候回調。它有一個參數,為當前表示音頻焦點對於當前應用的狀態代碼,通過這個狀態代碼指定對應的操作,有些時候音頻狀態改變了,並不一定需要停止音訊播放。
focusChange有一下幾種狀態代碼:
AUDIOFOCUS_GAIN:獲得音頻焦點。
AUDIOFOCUS_LOSS:失去音頻焦點,並且會持續很長時間。這是我們需要停止MediaPlayer的播放。
AUDIOFOCUS_LOSS_TRANSIENT:失去音頻焦點,但並不會持續很長時間,需要暫停MediaPlayer的播放,等待重新獲得音頻焦點。
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:暫時失去音頻焦點,但是無需停止播放,只需降低聲音方法。
audioManager = (AudioManager) getSystemService(this.AUDIO_SERVICE); int result = audioManager.requestAudioFocus( new OnAudioFocusChangeListener() { @Override public void onAudioFocusChange(int focusChange) { switch (focusChange) { case AudioManager.AUDIOFOCUS_GAIN: // 獲得音頻焦點 if (!mediaPlayer.isPlaying()) { mediaPlayer.start(); } // 還原音量 mediaPlayer.setVolume(1.0f, 1.0f); break; case AudioManager.AUDIOFOCUS_LOSS: // 長久的失去音頻焦點,釋放MediaPlayer if (mediaPlayer.isPlaying()) mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: // 展示失去音頻焦點,暫停播放等待重新獲得音頻焦點 if (mediaPlayer.isPlaying()) mediaPlayer.pause(); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // 失去音頻焦點,無需停止播放,降低聲音即可 if (mediaPlayer.isPlaying()) { mediaPlayer.setVolume(0.1f, 0.1f); } break; } } }, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
總結
以上就講解了MediaPlayer的一些進階的內容,在掌握了MediaPlayer的使用之後,開發有關音樂播放類的應用的時候就可以得心應手了。從使用者體驗的方面出發,如果真實開發一款播放器類的軟體,需要監聽AUDIO_BECOMING_NOISY的廣播,它會在音訊輸出源從其他輸出源變換到裝置擴音器的時候發出此廣播,監聽廣播在音訊輸出源改變到裝置擴音器的時候,停止播放,這樣確保在耳機或額外的音訊輸出硬體與裝置中斷連線的時候,不至於重新從擴音器繼續輸出音頻播放。
源碼連結:http://download.csdn.net/detail/duanyu218/7475569