Android開發之MdiaPlayer詳解
MediaPlayer類可用于控制音頻/視訊檔案或流的播放,我曾在《Android開發之基于Service的音樂播放器》一文中介紹過它的使用。下面讓我們看一下MediaPlayer類的詳細介紹。
一、類結構:
java.lang.Object
?
android.media.MediaPlayer
二、構造方法和公有方法
構造方法:
Public Constructors
MediaPlayer()
預設構造方法。
公有方法:
Public Methods
static MediaPlayer
create(Context context, Uri uri, SurfaceHolder holder)
指定從資源ID對應的資源檔案中來裝載音樂檔案,同時指定了SurfaceHolder對象并傳回MediaPlyaer對象。
create(Context context, int resid)
指定從資源ID對應的資源檔案中來裝載音樂檔案,并傳回新建立的MediaPlyaer對象。
create(Context context, Uri uri)
從指定Uri裝在音頻檔案,并傳回新建立的MediaPlayer對象。
int
getCurrentPosition()
擷取目前播放的位置。
getDuration()
擷取音頻的時長。
getVideoHeight()
擷取視訊的高度。
getVideoWidth()
擷取視訊的寬度。
boolean
isLooping()
判斷MediaPlayer是否正在循環播放。
isPlaying()
判斷MediaPlayer是否正在播放。
void
pause()
暫停播放。
prepare()
準備播放(裝載音頻),調用此方法會使MediaPlayer進入Prepared狀态。
prepareAsync()
準備播放異步音頻。
release()
釋放媒體資源。
reset()
重置MediaPlayer進入未初始化狀态。
seekTo(int msec)
尋找指定的時間位置。
setAudioStreamType(int streamtype)
設定音頻流的類型。
setDataSource(String path)
指定裝載path路徑所代表的檔案。
setDataSource(Context context, Uri uri, Map<String, String headers)
指定裝載uri所代表的檔案。
setDataSource(Context context, Uri uri)
setDataSource(FileDescriptor fd, long offset, long length)
指定裝載fd所代表的檔案中從offset開始長度為length的檔案内容。
setDataSource(FileDescriptor fd)
指定裝載fd所代表的檔案。
setDisplay(SurfaceHolder sh)
設定顯示方式。
setLooping(boolean looping)
設定是否循環播放。
setNextMediaPlayer(MediaPlayer next)
設定目前流媒體播放完畢,下一個播放的MediaPlayer。
setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener)
注冊一個回調函數,在網絡視訊流緩沖變化時調用。
setOnCompletionListener(MediaPlayer.OnCompletionListener listener)
為Media Player的播放完成事件綁定事件監聽器。
setOnErrorListener(MediaPlayer.OnErrorListener listener)
為MediaPlayer的播放錯誤事件綁定事件監聽器。
setOnPreparedListener(MediaPlayer.OnPreparedListener listener)
當MediaPlayer調用prepare()方法時觸發該監聽器。
setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener)
當MediaPlayer調用seek()方法時觸發該監聽器。
setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener)
注冊一個用于監聽視訊大小改變的監聽器。
setScreenOnWhilePlaying(boolean screenOn)
置是否使用SurfaceHolder來顯示。
setSurface(Surface surface)
設定Surface。
setVideoScalingMode(int mode)
設定視訊縮放的模式。
setVolume(float leftVolume, float rightVolume)
設定播放器的音量。
setWakeMode(Context context, int mode)
為MediaPlayer設定低級電源管理行為。.
start()
開始或恢複播放。
stop()
停止播放。
三、常用方法分析:
進度條SeekBar可以用來顯示播放進度,使用者也可以利用SeekBar的滑塊來控制音樂的播放。
SeekBar需要使用的一些方法:
setProgress(int value):設定滑塊的位置方法為。
setMax(int value):設定進度條的最大長度。
setOnSeekBarChangeListener(OnSeekBarChangeListener l):設定SeekBar的進度改變事件。
MusicPlayer需要使用的一些方法:
getDuration():獲得音樂長度為。
getCurrentPosition():獲得現在播放的位置。
seekTo(int msec):調用seekTo()方法可以調整播放的位置。
seekTo(int)方法是異步執行的,是以它可以馬上傳回,但是實際的定位播放操作可能需要一段時間才能完成,尤其是播放流形式的音頻/視訊。當實際的定位播放操作完成之後,内部的播放引擎會調用用戶端程式員提供的OnSeekComplete.onSeekComplete()回調方法。可以通過setOnSeekCompleteListener(OnSeekCompleteListener)方法注冊。
seekTo(int)方法也可以在其它狀态下調用,比如Prepared,Paused和PlaybackCompleted狀态。此外,目前的播放位置,實際可以調用getCurrentPosition()方法得到,它可以幫助如音樂播放器的應用程式不斷更新播放進度。
建立并使用進度條的步驟:
第一步:建立一個進度條
//進度條
static SeekBarskbMusic;
skbMusic=(SeekBar)findViewById(R.id.skbMusic);
第二步:為進度條的改變事件注冊并添加監聽器
skbMusic.setOnSeekBarChangeListener(sChangeListener);
/**
* SeekBar進度改變事件
*/
OnSeekBarChangeListenersChangeListener=new OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
//當拖動停止後,控制mediaPlayer播放指定位置的音樂
MusicService.mediaPlayer.seekTo(seekBar.getProgress());
MusicService.isChanging=false;
}
public void onStartTrackingTouch(SeekBar seekBar) {
MusicService.isChanging=true;
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
}
};
第三步:設定進度條的最大長度:
//getDuration()方法要在prepare()方法之後,否則會出現Attempt to call getDuration without a valid mediaplayer異常
MusicBox.skbMusic.setMax(mediaPlayer.getDuration());//設定SeekBar的長度
第四步:更新進度條
//----------定時器記錄播放進度---------//
mTimer =new Timer();
mTimerTask =new TimerTask() {
@Override
publicvoid run() {
isTimerRunning=true;
if(isChanging==true)//當使用者正在拖動進度進度條時不處理進度條的的進度
return;
MusicBox.skbMusic.setProgress(mediaPlayer.getCurrentPosition());
}
//每隔10毫秒檢測一下播放進度
mTimer.schedule(mTimerTask, 0, 10);
為了讓MediaPlayer來裝載指定音頻檔案,MediaPlayer提供了如下簡單的靜态方法。
static MediaPlayer create(Context context, Uri uri):從指定Uri來裝載音頻檔案,并傳回新建立的MediaPlayer對象。
static MediaPlayer create(Context context, int resid):從 resid資源 ID對應的資源檔案中裝載音頻檔案,并傳回新建立的MediaPlayer對象。
提示:上而這兩個方法用起來非常友善,但這兩個方法每次都會傳回新建立的MediaPlayer對象,如來程式需要使用MediaPlayer循環播放多個音頻檔案,使用MediaPlayer的靜态create方法就不太合适了,此時可通過MediaPlayer的setDataSource()方法來裝載指定的音頻檔案。MediaPlayer提供了如下方法來指定裝載相應的音頻檔案。
setDataSource(String path):指定裝載path路徑所代表的檔案。
setDataSource(FileDescriptor fd, long offset,long length):指定裝載fd所代表的檔案中從offset開始長度為length的檔案内容。
setDataSource(FileDescriptor fd):指定裝載fd所代表的檔案。
setDataSource(Context context, Uri uri):指定裝載uri所代表的檔案。
提示:執行上面所示的setDataSource()方法之後,MediaPlayer并未真正去裝載那些音頻檔案,還需要調用MediaPlayer的prepare()方法去準備音頻,所謂“準備”,就是讓MediaPlayer真正去裝載音頻檔案。
使用已有的MediaPlayer對象裝載“一首”歌曲的代碼模闆為:
mPlayer.reset();
//裝戰下一竹歌曲
mPlayer.setDataSource(M/mnt/sdcard/next.mp3);
//準備聲音 mPlayer.prepare();
"播放
mPlayer.start();
}
catch (IOException e)
e.printStackTrace();
MediaPlayer提供了一些綁定事件監聽器的方法,用于監聽MediaPlayer播放過程中所發生的特定事件,綁定事件監聽器的方法如下。
setOnCompletionListener(MediaPlayer.OnCompletionListener listener):為 Media Player的播放完成事件綁定事件監聽器。
setOnErrorListener(MediaPlayer.OnErrorListener listener):為MediaPlayer的播放錯誤事件綁定事件監聽器。
setOnPreparedListener(MediaPlayer.OnPreparedListener listener):當 MediaPlayer調用prepare()方法時觸發該監聽器。
setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener):當MediaPlayer調用seek()方法時觸發該監聽器。
是以可以在建立一個MediaPlayer對象之後,通過為該MediaPlayer綁定監聽器來監聽相應的事件,例如如下代碼:
//為MediaPlayer的播放完成事件綁定事件監聽器
mPlayer.setOnErrorListener(new OnErrorListener() {
publicboolean onError(MediaPlayer mp,int what,int extra) {
// TODO Auto-generated method stub
//針對錯誤進行相應的處理
// ... ...
});
//為MediaPlayer的播放完成講件綁定市件監聽器
mPlayer.setOnCompletionListener(new OnCompletionListener() {
publicvoid onCompletion(MediaPlayer mp) {
current++;
prepareAndPlay(current);
}
});
四、MediaPlayer播放不同來源的音頻檔案:
播放應用的資源檔案需要兩步即:
1) 調用MediaPlayer的create(Context context,int resid)方法加指定資源檔案。
2) 調用 MediaPlayer的 start()、pause()、stop()等方法控制播放即可。
例如如下代碼:
MediaPlayer mPlayer=new MediaPlayer();
mPlayer.create(this, R.raw.music);
播放應用的資源檔案按如下步驟執行。
1) 調用 Context的 getAssets()方法擷取應用的 AssetManager。
2) 調用AssetManager對象的openFd(String name)方法打開指定的原生資源,該方法傳回一個AssetFileDescriptor對象。
3) 調用 AssetFileDescriptor的 getFileDescriptor()、getStartOffset()和 getLength()方法來擷取音頻檔案的FileDescriptor、開始位置、長度等。
4) 建立MediaPlayer對象(或利用已有的MediaPlayer對象),并調用MediaPlayer對象的setDataSource(FileDescriptor fd,long offset, long length)方法來裝載音頻資源。
5) 調用MediaPlayer對象的prepare()方法準備音頻。
6) 調用MediaPlayer的start()、pause()、stop()等方法控制播放即可。
例如如下代碼片段:
//擷取assets目錄下指定檔案的AssetFileDescriptor對象
AssetFileDescriptor assetFileDescriptor=assetManager.openFd(musics[current]);
mediaPlayer.reset();//初始化mediaPlayer對象
mediaPlayer.setDataSource(assetFileDescriptor.getFileDescriptor(), assetFileDescriptor.getStartOffset(), assetFileDescriptor.getLength());
//準備播放音樂
mediaPlayer.prepare();
//播放音樂
mediaPlayer.start();
播放外部存儲器上音頻檔案按如下步驟執行。
1) 建立MediaPlayer對象(或利用已有的MediaPlayer對象),并調用MediaPlayer對象的setDateSource(String path)方法裝載指定的音頻檔案。
2) 調用MediaPlayer對象的prepare()方法準備音頻。
3) 調用MediaPlayer的start()、pause()、stop()等方法控制播放即可。
例如如下代碼:
//加載SD卡上的指定資源音頻檔案
mPlayer.setDataSource("/mnt/You Are The One.mp3");
mPlayer.prepare();//準備因音頻
mPlayer.start();//播放音頻
播放來自網絡的音頻檔案?兩種方式:1.直接使用MediaPlayer的靜态create(Context context, Uri uri)方法;2.調用 MediaPlayer的setDataSource(Context context,Uri uri)裝載指定Uri對應的音頻檔案。
以第二種方式播放來自網絡的音頻檔案的步驟如下。
1. 根據網絡上的音頻檔案所在的位置建立Uri對象。
2. 建立MediaPlayer對象(或利用己有的MediaPlayer對象),并調用MediaPlayer對象的 setDateSource(Context context,Uri uri)方法裝載Uri對應的音頻檔案。
3. 調用MediaPlayer對象的prepare()方法準備音頻。
4. 調用MediaPlayer的start()、pause()、stop()等方法控制播放即可。
Uri uri = Uri.parse("http://play.baidu.com/heihei.mp3");
MediaPlayer mPlayer = new MediaPlayer();
//使用MediaPlayer根據Uri來加載指定的聲音檔案
mPlayer.setDataSource(this, uri);
MediaPlayer除了調用prepare()方法來準備聲音之外,還以調用prepareAsync()來準備聲音,prepareAsync()與普通prepare()方法的差別在于,prepareAsync()是異步的,它不會阻塞目前的UI線程。
五、解析MdiaPlayer的狀态圖
上面這張狀态轉換圖清晰的描述了MediaPlayer的各個狀态,也列舉了主要的方法的調用時序,每種方法隻能在一些特定的狀态下使用,如果使用時MediaPlayer的狀态不正确則會引發IllegalStateException異常。
Idle狀态:當使用new()方法建立一個MediaPlayer對象或者調用了其reset()方法時,該MediaPlayer對象處于idle狀态。在處于Idle狀态時,調用getCurrentPosition(), getDuration(), getVideoHeight(),getVideoWidth(),setAudioStreamType(int), setLooping(boolean), setVolume(float, float), pause(), start(), stop(), seekTo(int), prepare()或者 prepareAsync()方法都會出現相應錯誤。這兩種方法的一個重要差别就是:當一個MediaPlayer對象剛被建構的時候,内部的播放引擎和對象的狀态都沒有改變,在這個時候調用以上的那些方法,架構将無法回調用戶端程式注冊的OnErrorListener.onError()方法,是以不會進入Error狀态;但若這個MediaPlayer對象調用了reset()方法之後,再調用以上的那些方法,内部的播放引擎就會回調用戶端程式注冊的OnErrorListener.onError()方法,這時MediaPlayer會進入Error狀态。
提示:使用new操作符建立的MediaPlayer對象處于Idle狀态,而那些通過重載的create()便利方法建立的MediaPlayer對象卻不是處于Idle狀态。事實上,如果成功調用了重載的create()方法,那麼這些對象已經是Prepare狀态了。
End狀态:通過release()方法可以進入End狀态,隻要MediaPlayer對象不再被使用,就應當盡快将其通過release()方法釋放掉,以釋放相關的軟硬體元件資源,這其中有些資源是隻有一份的(相當于臨界資源)。如果MediaPlayer對象進入了End狀态,則不會再進入任何其他狀态了。
Initialized狀态:這個狀态比較簡單,MediaPlayer調用setDataSource()方法就進入Initialized狀态,表示此時要播放的檔案已經設定好了。
提示:若當此MediaPlayer處于其它的狀态下,調用setDataSource()方法,會抛出IllegalStateException異常。
Prepared狀态:初始化完成之後還需要通過調用prepare()或prepareAsync()方法,這兩個方法一個是同步的一個是異步的,隻有進入Prepared狀态,才表明MediaPlayer到目前為止都沒有錯誤,可以進行檔案播放。
提示:在不合适的狀态下調用prepare()和prepareAsync()方法會抛出IllegalStateException異常。當MediaPlayer對象處于Prepared狀态的時候,可以調整音頻/視訊的屬性,如音量,播放時是否一直亮屏,循環播放等。
Preparing狀态:這個狀态比較好了解,主要是和prepareAsync()配合,如果異步準備完成,會觸發OnPreparedListener.onPrepared(),進而進入Prepared狀态。
Started狀态:顯然,MediaPlayer一旦準備好,就可以調用start()方法,這樣MediaPlayer就處于Started狀态,這表明MediaPlayer正在播放檔案過程中。可以使用isPlaying()測試MediaPlayer是否處于了Started狀态。如果播放完畢,而又設定了循環播放,則MediaPlayer仍然會處于Started狀态,類似的,如果在該狀态下MediaPlayer調用了seekTo()或者start()方法均可以讓MediaPlayer停留在Started狀态。
Paused狀态:Started狀态下MediaPlayer調用pause()方法可以暫停MediaPlayer,進而進入Paused狀态,MediaPlayer暫停後再次調用start()則可以繼續MediaPlayer的播放,轉到Started狀态,暫停狀态時可以調用seekTo()方法,這是不會改變狀态的。
Stop狀态:Started或者Paused狀态下均可調用stop()停止MediaPlayer,而處于Stop狀态的MediaPlayer要想重新播放,需要通過prepareAsync()和prepare()回到先前的Prepared狀态重新開始才可以。
PlaybackCompleted狀态:檔案正常播放完畢,而又沒有設定循環播放的話就進入該狀态,并會觸發OnCompletionListener的onCompletion()方法。此時可以調用start()方法重新從頭播放檔案,也可以stop()停止MediaPlayer,或者也可以seekTo()來重新定位播放位置。
Error狀态:在一般情況下,由于種種原因一些播放控制操作可能會失敗,如不支援的音頻/視訊格式,缺少隔行掃描的音頻/視訊,分辨率太高,流逾時等原因,等等會觸發會觸發OnErrorListener.onError()事件,此時MediaPlayer會進入Error狀态,及時捕捉并妥善處理這些錯誤是很重要的,可以幫助我們及時釋放相關的軟硬體資源,也可以改善使用者體驗。
開發者可以通過setOnErrorListener(android.media.MediaPlayer.OnErrorListener設定監聽器來監聽MediaPlayer是否進入Error狀态。如果MediaPlayer進入了Error狀态,可以通過調用reset()來恢複,使得MediaPlayer重新傳回到Idle狀态。
本文轉自 一點點征服 部落格園部落格,原文連結:http://www.cnblogs.com/ldq2016/p/5365080.html,如需轉載請自行聯系原作者