Android開發之MdiaPlayer詳解


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對象。

static MediaPlayer

create(Context context, int resid)

指定從資源ID對應的資源文件中來裝載音樂文件,並返回新創建的MediaPlyaer對象。

static MediaPlayer

create(Context context, Uri uri)

從指定Uri裝在音頻文件,並返回新創建的MediaPlayer對象。

int

getCurrentPosition()

獲取當前播放的位置。

int

getDuration()

獲取音頻的時長。

int

getVideoHeight()

獲取視頻的高度。

int

getVideoWidth()

獲取視頻的寬度。

boolean

isLooping()

判斷MediaPlayer是否正在循環播放。

boolean

isPlaying()

判斷MediaPlayer是否正在播放。

void

pause()

暫停播放。

void

prepare()

准備播放(裝載音頻),調用此方法會使MediaPlayer進入Prepared狀態。

void

prepareAsync()

准備播放異步音頻。

void

release()

釋放媒體資源。

void

reset()

重置MediaPlayer進入未初始化狀態。

void

seekTo(int msec)

尋找指定的時間位置。

void

setAudioStreamType(int streamtype)

設置音頻流的類型。

void

setDataSource(String path)

指定裝載path路徑所代表的文件。

void

setDataSource(Context context, Uri uri, Map<String, String headers)

指定裝載uri所代表的文件。

void

setDataSource(Context context, Uri uri)

指定裝載uri所代表的文件。

void

setDataSource(FileDescriptor fd, long offset, long length)

指定裝載fd所代表的文件中從offset開始長度為length的文件內容。

void

setDataSource(FileDescriptor fd)

指定裝載fd所代表的文件。

void

setDisplay(SurfaceHolder sh)

設置顯示方式。

void

setLooping(boolean looping)

設置是否循環播放。

void

setNextMediaPlayer(MediaPlayer next)

設置當前流媒體播放完畢,下一個播放的MediaPlayer。

void

setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener)

注冊一個回調函數,在網絡視頻流緩沖變化時調用。

void

setOnCompletionListener(MediaPlayer.OnCompletionListener listener)

為Media Player的播放完成事件綁定事件監聽器。

void

setOnErrorListener(MediaPlayer.OnErrorListener listener)

為MediaPlayer的播放錯誤事件綁定事件監聽器。

void

setOnPreparedListener(MediaPlayer.OnPreparedListener listener)

當MediaPlayer調用prepare()方法時觸發該監聽器。

void

setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener)

當MediaPlayer調用seek()方法時觸發該監聽器。

void

setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener)

注冊一個用於監聽視頻大小改變的監聽器。

void

setScreenOnWhilePlaying(boolean screenOn)

置是否使用SurfaceHolder來顯示。

void

setSurface(Surface surface)

設置Surface。

void

setVideoScalingMode(int mode)

設置視頻縮放的模式。

void

setVolume(float leftVolume, float rightVolume)

設置播放器的音量。

void

setWakeMode(Context context, int mode)

為MediaPlayer設置低級電源管理行為。.

void

start()

開始或恢復播放。

void

stop()

停止播放。

 

三、常用方法分析:

1.使用進度條:

進度條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;  

        }       

        @Override

        public void onStartTrackingTouch(SeekBar seekBar) {

                  // TODO Auto-generated method stub

                  MusicService.isChanging=true;

        }       

        @Override

        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);

 

2.裝載音頻文件:

為了讓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();

}

 

3.與MediaPlayer有關的事件監聽器:

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() {         

    @Override

    publicboolean onError(MediaPlayer mp,int what,int extra) {       

        // TODO Auto-generated method stub

        //針對錯誤進行相應的處理

//             ... ...

    }

});

//為MediaPlayer的播放完成講件綁定市件監聽器

mPlayer.setOnCompletionListener(new OnCompletionListener() {           

    @Override

    publicvoid onCompletion(MediaPlayer mp) {

        // TODO Auto-generated method stub

           current++;

           prepareAndPlay(current);   

        }

   });

 

四、MediaPlayer播放不同來源的音頻文件:

1.播放應用的資源文件

播放應用的資源文件需要兩步即:

1) 調用MediaPlayer的create(Context context,int resid)方法加指定資源文件。

2) 調用 MediaPlayer的 start()、pause()、stop()等方法控制播放即可。

例如如下代碼:

MediaPlayer mPlayer=new MediaPlayer();

mPlayer.create(this, R.raw.music);

 

2.  播放應用的原始資源文件

播放應用的資源文件按如下步驟執行。

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();

3.  播放外部存儲器上音頻文件

播放外部存儲器上音頻文件按如下步驟執行。

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();//播放音頻

4.播放來自網絡的音頻文件

播放來自網絡的音頻文件?兩種方式: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);

mPlayer.prepare();//准備因音頻

mPlayer.start();//播放音頻

MediaPlayer除了調用prepare()方法來准備聲音之外,還以調用prepareAsync()來准備聲音,prepareAsync()與普通prepare()方法的區別在於,prepareAsync()是異步的,它不會阻塞當前的UI線程。

五、解析MdiaPlayer的狀態圖

mediaplayer狀態圖

上面這張狀態轉換圖清晰的描述了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狀態。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM