基於Android的MediaPlayer的音樂播放器的封裝

潘永強_PandaPan發表於2017-02-18

基於Android的MediaPlayer的音樂播放器的封裝

使用過android原生的mediaplayer來做音訊播放的同學們,肯定是經歷過一些痛苦的,因為android提供了一個狀態機,確實這個狀態機是需要的,不過這個狀態不對,就要往外丟擲異常,並且如果在程式中,不能得知mediaplayr的狀態,這個是著實讓人頭疼,個人之前寫過mediaplayer的一個封裝,將這些狀態的獲取以及操作進行了簡化

封裝的連結地址: PandaPan音訊處理

1 原生的mediaplayer

android原生的mediaplayer,簡單做一下介紹,mediaplayer顧名思義,就是用於多媒體播放的,這個類,是可以做音訊和視訊流的播放的是基於android的多媒體框架做的,android的多媒體框架,支援的音訊格式也是有限的, 支援的格式的連結如下: android多媒體支援的格式, 能夠看到,其實還是挺頭疼的, 要想在android的主流版本上支援一些高清的格式,例如flac,ape等,你看,mediaplayer還是不靠譜的,那就得自己做這塊的音訊的解析啦, 可以有幾種方式,

方式1: native解碼, java層操作

一種就是使用原生的解碼器,解出來為pcm資料,然後使用android的audio來播放,不過這種方式,還需要將資料通過native層解析,然後交給java層來處理,這種方式呢,比較適合我們找到對應的codec,來處理,而這些codec,官方是提供的,但是針對不同的格式,也是需要自己寫不同的java層,來封裝好各種格式的資料,最終給audioTrack來使用,挺費勁的

方式2: native解碼與播放

就是將解碼與播放,都使用native來播放,android的native播放音訊模組是OpenSL ES,這種方式比較好,原因如下:

  1. native效率高,不需要和java層多次互動
  2. 我們java工程師,需要做的事情就比較少啦,哈哈

說了這些擦邊的,迴歸到正題

為什麼要做再次的封裝,原因彙總如下:

  1. android 原生的mediaplayer,容易丟擲異常,而且沒有狀態的獲取,很容易出現問題
  2. android的音訊狀態機設計的也是比較複雜的,你看看官網中提供的這個狀態機的圖 android的mediaplayer的狀態機圖 當然也是因為android的官方,做的很細緻,但是這給我們只是想播放音訊帶來了一些麻煩
  3. 可替換性不強,因為直接使用mediaplayer的相關介面,假如我們要播放一些我們不支援的音訊的格式的話,那麼估計就要寫很多的if else了,這樣肯定不是我們想要的,我們想用的是介面簡單方便使用,而且可以替換的,那麼這就涉及面向介面的程式設計啦

2 mediaplayer的再次設計

上面說的原因那麼多,這其實就是我們再次設計的需求:轉換為對應的需求:

  1. 提供介面,支援播放,暫停,繼續播放,停止播放,seekTo()
  2. 獲取當前播放器的狀態,獲取播放的路徑, 時長, 是否正在播放
  3. 提供介面,可以對其設定監聽,可以得知當前播放器狀態的變化

2.1 狀態的再次設計

基於這麼幾點,以及android原生播放器的狀態圖,以及在不同狀態支援的操作,我將android的mediaplayer的狀態進行了簡化.

總共有五個狀態

  • 空閒狀態 IDLE (對應mediaplayer中的Idle)
  • 初始化狀態 INITIALIZED(對應MediaPlayer的Initialized)
  • 準備中的狀態 PREPARING (對應MediaPlayer的Preparing)
  • 準備好的狀態 PREPARED (對應mediaplayer的Prepared)
  • 執行中的狀態 RUNNING (對應mediaplayer的Started +Paused)

大家可能會有疑問,那麼其他的狀態,其實其他的狀態被我直接給簡化處理了

圖中的End,ErrorPlayerbackComplete狀態都直接將mediaplayer給清空了,將Mediaplayer直接重新設定為新的mediaplayer,恢復到了IDLE狀態,因而簡化了N多操作

2.2 向外通知變化

上面我們提供的狀態變化,會向外做通知

Preparing –> Prepared –> (Pause + Play) – {OnErro/OnStopped/OnComplete}

OnProgressChanged

2.3 疑問解答

大家可能會提到,為什麼不把迴圈播放,以及自動播放下一首放到這個類實現?願意如下:

  1. 類要分功能和模組,這個類,只是用作狀態的封裝,不應該新增其他功能
  2. 在正常的工程中,我們要實現的迴圈播放,對應的資料,應該不只是簡單的一個路徑,對應的肯定是一些MediaInfo的資料,可能有title,artist等資料,這個我可以後續再次新增一個類,做這樣的功能,內部呼叫StatedMediaPlayer即可

工程程式碼

封裝的連結地址: PandaPan音訊處理 這個工程下的類地址:

https://github.com/yqpan1991/DroidAudio/blob/master/app/src/main/java/droidaudio/apollo/edus/com/droidaudio/multimedia/media/StatedMediaPlay.java

相關文章