編輯:關於Android編程
前言
之前博客裡已經將了MediaPlayer的簡單應用,如何使用MediaPlayer在Android應用中播放音頻。這篇博客在MediaPlayer使用的基礎上,講解一下MediaPlayer的一些高級功能的使用,以及它的狀態轉換。對MediaPlayer還不了解的朋友可以先看看之前那篇博客:Android--MP3播放器MediaPlayer。
本篇博客主要內容如下:
MediaPlayer的狀態變換
之前講到,使用MediaPlayer播放音頻,主要使用的是start()、pause()、stop()等方法操作MediaPlayer。但是除了開始、暫停、停止等,MediaPlayer還涉及到一些其他的狀態切換,有些狀態是可以雙向轉換的,有些只能單向環形轉換。如果在某狀態下,強行轉換狀態,會應發程序錯誤,例如在Preparing狀態下切換到Started狀態,是准備中強行開始播放,會出錯。下圖是官方文檔上的圖例,可以很清晰的表名MediaPlayer各個狀態的轉換情況。
上圖已經對MediaPlayer的各種狀態轉換有的清晰的介紹,這裡不再詳細講解了,只是提一下需要注意的地方:
一般對於鎖而言,鎖定了通常需要解鎖,但是這裡的喚醒說與MediaPlayer關聯,所以只需要在使用完之後release()釋放MediaPlayer即可,無需顯式的為其解鎖。在使用setWakeMode設定喚醒鎖的時候,還必須為應用賦予相應的權限:
再來說說如何鎖定wifi硬件在系統睡眠的時候保持正常運行。wifi鎖通過WifiLock進行操作,而WifiLock通過WifiManager進行管理,通過WifiManager.createWifiLock()進行Wifi鎖定。
WifiManager.WifiLock createWifiLock(int lockType, String tag)
這個方法有多個重載,這裡介紹的這個,第一個參數設定鎖的狀態,為一個int類型的常量,定義在Context類中,這裡的應用場景一般設定為WIFI_MODE_FULL即可。第二個參數為WifiLock的標志,用於確定wifiLock的。
1 wifiLock= ((WifiManager) getSystemService(this.WIFI_SERVICE)) 2 .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock"); 3 wifiLock.acquire();
當然,在應用中把Wifi鎖定之後,還需要在MediaPlayer.release()的時候為wifi硬件解鎖,為避免意外關閉的情況,最好在Android組件的onDestory()裡對其進行釋放,釋放Wifi鎖使用WifiLock.release()。
1 /** 2 * 停止播放 3 */ 4 protected void stop() { 5 if (mediaPlayer != null && mediaPlayer.isPlaying()) { 6 mediaPlayer.stop(); 7 mediaPlayer.release(); 8 mediaPlayer = null; 9 // 釋放wifi鎖 10 wifiLock.acquire(); 11 btn_play.setEnabled(true); 12 Toast.makeText(this, "停止播放", 0).show(); 13 } 14 15 } 16 17 @Override 18 protected void onDestroy() { 19 // 在activity結束的時候回收資源 20 if (mediaPlayer != null && mediaPlayer.isPlaying()) { 21 mediaPlayer.stop(); 22 mediaPlayer.release(); 23 mediaPlayer = null; 24 // 釋放wifi鎖 25 wifiLock.acquire(); 26 } 27 super.onDestroy(); 28 }
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有一下幾種狀態碼:
1 audioManager = (AudioManager) getSystemService(this.AUDIO_SERVICE); 2 int result = audioManager.requestAudioFocus( 3 new OnAudioFocusChangeListener() { 4 5 @Override 6 public void onAudioFocusChange(int focusChange) { 7 switch (focusChange) { 8 case AudioManager.AUDIOFOCUS_GAIN: 9 // 獲得音頻焦點 10 if (!mediaPlayer.isPlaying()) { 11 mediaPlayer.start(); 12 } 13 // 還原音量 14 mediaPlayer.setVolume(1.0f, 1.0f); 15 break; 16 17 case AudioManager.AUDIOFOCUS_LOSS: 18 // 長久的失去音頻焦點,釋放MediaPlayer 19 if (mediaPlayer.isPlaying()) 20 mediaPlayer.stop(); 21 mediaPlayer.release(); 22 mediaPlayer = null; 23 break; 24 25 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: 26 // 展示失去音頻焦點,暫停播放等待重新獲得音頻焦點 27 if (mediaPlayer.isPlaying()) 28 mediaPlayer.pause(); 29 break; 30 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: 31 // 失去音頻焦點,無需停止播放,降低聲音即可 32 if (mediaPlayer.isPlaying()) { 33 mediaPlayer.setVolume(0.1f, 0.1f); 34 } 35 break; 36 } 37 } 38 }, AudioManager.STREAM_MUSIC, 39 AudioManager.AUDIOFOCUS_GAIN);
源碼下載
總結
以上就講解了MediaPlayer的一些高級的內容,在掌握了MediaPlayer的使用之後,開發有關音樂播放類的應用的時候就可以得心應手了。從用戶體驗的方面出發,如果真實開發一款播放器類的軟件,需要監聽AUDIO_BECOMING_NOISY的廣播,它會在音頻輸出源從其他輸出源變換到設備揚聲器的時候發出此廣播,監聽廣播在音頻輸出源改變到設備揚聲器的時候,停止播放,這樣確保在耳機或額外的音頻輸出硬件與設備斷開連接的時候,不至於重新從揚聲器繼續輸出音頻播放。
前面幾篇文章學習了AndroidStudio插件的基礎後,這篇文章打算開發一個酷炫一點的插件。因為會用到前面的基礎,所以如果沒有看前面系列文章的話,請先返回。當然,如果有
一、前言自從上次發表了打造android萬能上拉下拉刷新框架——XRefreshView (一)之後,期間的大半個月一直都很忙,但是我每天晚上下班
方法一:Android的界面布局可以用兩種方法,一種是在xml中布局,一種是和JAVA中Swing一樣在JAVA代碼中實現Ui界面的布局,用xml的布局管理器布局是很方便
前幾天在“Android繪圖之漸隱動畫”一文中通過畫線實現了漸隱動畫,但裡面有個問題,畫筆較粗(大於1)時線段之間會有裂隙,我又改進了一下。這次效果好多了。先看效果吧:然