android提供了常見的音頻、視訊的編碼、解碼機制。借助于多媒體類mediaplayer的支援,開發人員可以很友善在在應用中播放音頻、視訊。本篇部落客要講解在android平台下如何播放一個音頻檔案。
本篇部落客要内容如下:
<a target="_blank" href="http://www.cnblogs.com/plokmju/p/android_mediaplayer.html#mediaplayer">mediaplayer</a>
<a target="_blank" href="http://www.cnblogs.com/plokmju/p/android_mediaplayer.html#audiosource">mediaplayer的音頻源</a>
<a target="_blank" href="http://www.cnblogs.com/plokmju/p/android_mediaplayer.html#usermediaplayer">使用mediaplayer播放音樂</a>
<a target="_blank" href="http://www.cnblogs.com/plokmju/p/android_mediaplayer.html#userskill">mediaplayer使用技巧</a>
<a target="_blank" href="http://www.cnblogs.com/plokmju/p/android_mediaplayer.html#mp3demo">demo--一個簡單的mp3播放器</a>
mediaplayer
上面提到過,android下對于音頻、視訊的支援均需要使用到mediaplayer,它主要用來控制android下播放檔案或流的類。mediaplayer處于android多媒體包下"android.media.mediaplayer",僅有一個無參的構造函數,雖然僅為我們提供了一個無參的構造函數,為了友善我們初始化,還為我們提供了幾個靜态的create()方法用于完成mediaplayer初始化的工作。
static mediaplayer create(context context,int resid):通過音頻資源的id來建立一個mediaplayer執行個體。
static mediaplayer create(context context,uri uri):通過一個音頻資源的uri位址來建立一個mediaplayer執行個體。
mediaplayer除了通過上面兩個create()方法在初始化的時候指定媒體資源,還可以通過mediaplayer.setdatasource()方法為初始化後的mediaplayer設定媒體資源,setdatasource()具有多個重載函數,适用于不同的媒體資源來源,以下講解幾個常用的,其他的可以查閱官方文檔。
void setdatasource(string path):通過一個媒體資源的位址指定mediaplayer的資料源,這裡的path可以是一個本地路徑,也可以是網絡路徑。
void setdatasource(context context,uri uri):通過一個uri指定mediaplayer的資料源,這裡的uri可以是網絡路徑或這一個内容提供者的uri。
void setdatasource(filedescriptor fd):通過一個filedescriptor指定一個mediaplayer的資料源。
通過上面介紹的初始化mediaplayer的播放時媒體資料源的方法可以看出,mediaplayer支援的資料源有:本地檔案、内部的uri(内容提供者)、外部uri。
如,設定一個本地sd卡的資源:
注意讀記憶體卡,還需要設定通路記憶體卡的權限:
如,設定一個外部uri的網絡流媒體資源:
如果通路網絡流媒體資源,還需要設定通路網絡的權限:
mediaplayer其實是一個封裝的很好的音頻、視訊流媒體操作類,如果檢視其源碼,會發現其内部是調用的native方法,是以它其實是有c++實作的。
既然是一個流媒體操作類,那麼必然涉及到,播放、暫停、停止等操作,實際上mediaplayer也為我們提供了相應的方法來直接操作流媒體。
void start():開始或恢複播放。
void stop():停止播放。
void pause():暫停播放。
通過上面三個方法,隻要設定好流媒體資料源,即可在應用中播放流媒體資源,為了更好的操作流媒體,mediaplayer還為我們提供了一些其他的方法,這裡列出一些常用的,詳細内容參閱官方文檔。
int getduration():擷取流媒體的總播放時長,機關是毫秒。
int getcurrentposition():擷取目前流媒體的播放的位置,機關是毫秒。
void seekto(int msec):設定目前mediaplayer的播放位置,機關是毫秒。
void setlooping(boolean looping):設定是否循環播放。
boolean islooping():判斷是否循環播放。
boolean isplaying():判斷是否正在播放。
void prepare():同步的方式裝載流媒體檔案。
void prepareasync():異步的方式裝載流媒體檔案。
void release ():回收流媒體資源。
void setaudiostreamtype(int streamtype):設定播放流媒體類型。
void setwakemode(context context, int mode):設定cpu喚醒的狀态。
setnextmediaplayer(mediaplayer next):設定目前流媒體播放完畢,下一個播放的mediaplayer。
大部分方法的看方法名就可以了解,但是有幾個方法需要單獨說明一下。
在使用mediaplayer播放一段流媒體的時候,需要使用prepare()或prepareasync()方法把流媒體裝載進mediaplayer,才可以調用start()方法播放流媒體。
setaudiostreamtype()方法用于指定播放流媒體的類型,它傳遞的是一個int類型的資料,均以常量定義在audiomanager類中, 一般我們播放音頻檔案,設定為audiomanager.stream_music即可。
除了上面介紹的一些方法外,mediaplayer還提供了一些事件的回調函數,這裡介紹幾個常用的:
setoncompletionlistener(mediaplayer.oncompletionlistener listener):當流媒體播放完畢的時候回調。
setonerrorlistener(mediaplayer.onerrorlistener listener):當播放中發生錯誤的時候回調。
setonpreparedlistener(mediaplayer.onpreparedlistener listener):當裝載流媒體完畢的時候回調。
setonseekcompletelistener(mediaplayer.onseekcompletelistener listener):當使用seekto()設定播放位置的時候回調。
在使用mediaplayer的使用過程中,有個小技巧需要說明一下:
1、在使用start()播放流媒體之前,需要裝載流媒體資源。這裡最好使用prepareasync()用異步的方式裝載流媒體資源。因為流媒體資源的裝載是會消耗系統資源的,在一些硬體不理想的裝置上,如果使用prepare()同步的方式裝載資源,可能會造成ui界面的卡頓,這是非常影響用于體驗的。因為推薦使用異步裝載的方式,為了避免還沒有裝載完成就調用start()而報錯的問題,需要綁定mediaplayer.setonpreparedlistener()事件,它将在異步裝載完成之後回調。異步裝載還有一個好處就是避免裝載逾時引發anr((application
not responding)錯誤。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
2、使用完mediaplayer需要回收資源。mediaplayer是很消耗系統資源的,是以在使用完mediaplayer,不要等待系統自動回收,最好是主動回收資源。
3、使用mediaplayer最好使用一個service來使用,并且在service的ondestory()方法中回收mediaplayer資源,實際上,就算是直接使用activity承載mediaplayer,也最好在銷毀的時候判斷一下mediaplayer是否被回收,如果未被回收,回收其資源,因為底層調用的native方法,如果不銷毀還是會在底層繼續播放,而承載的元件已經被銷毀了,這個時候就無法擷取到這個mediaplayer進而控制它。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
4、對于單曲循環之類的操作,除了可以使用setlooping()方法進行設定之外,還可以為mediaplayer注冊回調函數,mediaplayer.setoncompletionlistener(),它會在mediaplayer播放完畢被回調。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
5、因為mediaplayer一直操作的是一個流媒體,是以無可避免的可能一段流媒體資源,前半段可以正常播放,而中間一段因為解析或者源檔案錯誤等問題,造成中間一段無法播放問題,需要我們處理這個錯誤,否則會影響ux(使用者體驗)。可以為mediaplayer注冊回調函數setonerrorlistener()來設定出錯之後的解決辦法,一般重新播放或者播放下一個流媒體即可。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
上面已經介紹了mediaplayer播放一段音頻檔案的所有需要用到的内容。下面通過一個簡單的demo來示範如何使用mediaplayer播放一個sd卡上的mp3檔案。操作mediaplayer應該放在service中完成,這裡為了簡單,使用activity直接操作mediaplayer。代碼注釋裡寫的很清楚裡,這裡不再累述。
執行這個示例需要在/sdcard/目錄下存在xm.mp3的檔案。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
效果展示: