解讀官方Android MediaPlayer API(1)

在下李逍遙發表於2016-08-31
public class MediaPlayer

extends Object

MediaPlayer class 能夠用來使用來控制vudio/video(音訊或視訊)檔案和流檔案的播放.舉個例子可以在

VideoView 中瞭解怎麼樣使用這些方法。請看Audio and Video 中附加的文件。

MedioPlayer狀態圖如下:

audio/video(音訊/視訊)檔案和流的控制是通過狀態機制管理的。以下圖示顯示了 MediaPlayer 物件在播

放控制操作支援下被執行的生命週期和狀態。橢圓代表MedioPlayer物件可能駐留的狀態。弧線代表播放控制

操作驅使物件的狀態間的轉換。這裡有兩種弧線型別。單箭頭的弧線代表同步的方法呼叫,而雙箭頭的弧線代

表非同步的方法呼叫。

從狀態圖,我們可以知道MedioPlayer物件有以下的狀態:

1 ) 當使用new或呼叫reset()後MedioPlayer物件就會被建立,物件將處在Idle狀態;並且當release()被呼叫後,

物件將處於End狀態。 這兩種狀態之間是MedioPlayer物件的生命週期。

1.1) 這裡有點微妙但又很重要的不同是在MedioPlayer物件的建立和建立並呼叫reset()之後的MedioPlayer物件中

在Idle狀態時呼叫例如getCurrentPosition(), getDuration(), getVideoHeight(), getVideoWidth(),

setAudioStreamType(int) setLooping(boolean), setVolume(float, float), pause(), start(), stop(), seekTo(int)

prepare() or prepareAsync() 這些方法,都程式設計的錯誤。在MediaPlayer物件被構建後如果這些方法被呼叫,框架將無法被

內部的播放引擎回撥OnErrorListener.onError() 並且物件的狀態不會改變。但如果MediaPlayer物件呼叫了reset()之後,調

用這些方法,內部的播放引擎將能夠回撥 OnErrorListener.onError()方法,並且物件會轉入Error狀態。

1.2)並且推薦一旦MediaPlayer不再使用,就立即呼叫release()方法那麼內部播放引擎對這個MediaPlayer物件的關聯將會立即釋放資源。

資源包括單一的資源例如計算機加速硬體元件(可理解為只能夠一個物件使用的資源),所以若沒有呼叫release()方法可能會導致後面

的MediaPlayer物件無法使用這單一資源 從而退回到軟體實現或執行失敗,一旦MediaPlayer物件進入了End狀態,它將不再被使

用,並且沒有辦法回到其他任何狀態。

1.3)此外,使用new建立的MediaPlayer物件將處於Idle狀態,然而那些通過過載的create()便利方法建立的MediaPlayer物件卻不是出在Idle狀態。

實際上,如果成功呼叫create()方法,那麼這些物件將是處在Prepared狀態。

2)通常,一些播放控制操作由於各種各樣的原因而執行失敗,例如 audio/video的格式不支援;缺少隔行掃描的audio/video;分表率太高;流超時等此類原因。

那麼,錯誤的報告和恢復在這些情況下是重要的。有時,由於程式設計的錯誤,在一個無效的狀態下呼叫一個播放控制操作也可能發生。在所有這些錯誤條件下,

內部的播放引擎會呼叫一個由客戶端程式設計師提供的OnErrorListener.onError()方法。客戶端程式設計師可以通過呼叫Medialayer.setOnErrorListener(android.media.

MediaPlayer.OnErrorListener)方法來註冊OnErrorListener.

2.1)一旦錯誤發生,值得注意的是,MediaPlayer物件會進入Error狀態,即使沒有註冊OnErrorListener,應用還是會進入Error狀態。

2.2)為了重新使用在Error狀態的MediaPlayer物件使它從Error狀態恢復,那麼reset()方法的呼叫能夠恢復物件到Idle狀態。

2.3)一個好的程式設計實踐你的應用,是有註冊一個OnErrorListener用來注意來自內部播放引擎的Error的通知。

2.4)在一個invalid狀態下, 例如呼叫prepare(),   prepareAsync(),或者一個重寫的setDataSource方法。IlleglStateException異常被丟擲,可以防止程式設計的錯誤.。

3)呼叫setDataSource(FileDescriptor)方法,或setDataSource(String)方法,或setDataSource(Context,Uri)方法,

setDataSource(FileDescriptor,long,long)方法會使處於Idle狀態的物件遷移到Initialized狀態。

3.1)若當物件在任何一個其他狀態下呼叫setDataSource()會丟擲 IllegalStateException 異常。

3.2)好的程式設計習慣是不要疏忽了呼叫setDataSource()方法的時候可能會丟擲的IllegalArgumentException異常和IOException異常。 

4)一個MedioPlayer物件在播放開始之前必須首先進入Prepared狀態。

4.1)有兩種方法(同步和非同步)可以使MediaPlayer物件進入Prepared狀態:要麼呼叫prepare()方法(同步),

此方法返回就表示該MediaPlayer象已經進入了Prepared狀態;要麼呼叫prepareAsync()方法(非同步),此方法會使此

MediaPlayer物件進入Preparing狀態並返回,而內部的播放引擎會繼續未完成的準備工作。當同步版本返回時或非同步版本

的準備工作完全完成時就會呼叫客戶端程式設計師提供的OnPreparedListener.onPrepared()監聽方法。可以調MediaPlayer

.setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener)方法來註冊OnPreparedListener.

4.2)值得注意的是Preparing是個短暫的狀態,在此狀態下呼叫任何具備邊影響的方法的結果都是未知的!

4.3)在任何其他狀態下,呼叫prepare()prepareAsync()方法會丟擲IllegalStateException異常。

4.4)當MediaPlayer物件處於Prepared狀態的時候,可以呼叫相應的方法調整音訊/視訊的屬性,如音量,

播放時是否一直亮屏,迴圈播放等。 

5)想要開始播放,start()必須需要呼叫。在start()成功的呼叫之後MediaPlayer 物件將進入 Started的狀態,isPlaying()方法可

以被呼叫來測試某個MediaPlayer物件是否在Started狀態。

5.1)當在 Started狀態,內部播放引擎會呼叫客戶端程式設計師提供的OnBufferingUpdateListener.onBufferingUpdate()回撥方法,

通過setOnBufferingUpdateListener(OnBufferingUpdateListener)註冊監聽。此回撥方法允許應用程式追蹤流播放的緩衝的狀態。

5.2)對一個已經處於Started 狀態的MediaPlayer物件呼叫start()方法沒有影響。

6)播放可以被暫停,停止,和調整當前的播放位置。當呼叫pause()方法並返回時,會使MediaPlayer物件進入Paused狀態。

注意StartedPaused狀態的相互轉換在內部的播放引擎中是非同步的。所以可能需要一點時間在isPlaying()方法中更新

狀態,若在播放流內容,這段時間可能會有幾秒鐘。

6.1) 呼叫start()方法會讓一個處於Paused狀態的MediaPlayer物件從之前暫停的地方恢復播放。當呼叫start()方法

返回的時候,MediaPlayer物件的狀態會又變成Started狀態。


6.2) 對一個已經處於Paused狀態的MediaPlayer物件pause()方法沒有影響。

7) 呼叫stop()方法會停止播放,並且還會讓一個處於StartedPausedPreparedPlaybackCompleted狀態的MediaPlayer進入Stopped狀態。

7.1)一旦MediaPlayer在Stopped狀態,mediaPlayer不能開始播放,直到prepare() or prepareAsync()呼叫後,

使MediaPlayer再次進入Prepared狀態之後。

7.2)對一個已經處於Stopped狀態的MediaPlayer物件stop()方法沒有影響。

8) 呼叫seekTo()方法可以調整播放的位置。

8.1)seekTo(int)方法是非同步執行的,所以它可以馬上返回,但是實際的定位播放操作可能需要一段時間才能完成,

尤其是播放流形式的音訊/視訊。當實際的定位播放操作完成之後,內部的播放引擎會呼叫客戶端程式設計師提供的

OnSeekComplete.onSeekComplete()回撥方法。可以通過setOnSeekCompleteListener(OnSeekCompleteListener)方法註冊。

8.2)注意,seekTo(int)方法也可以在其它狀態下呼叫,比如PreparedPausedPlaybackCompleted狀態。

8.3)此外,目前的播放位置,實際可以呼叫getCurrentPosition()方法得到,它可以幫助如音樂播放器的應用程式不斷更新播放進度

9) 當播放到流的末尾,播放就完成了。

9.1) 如果呼叫了setLooping(boolean)方法開啟了迴圈模式,那麼這個MediaPlayer物件會重新進入Started狀態。



9.2) 若沒有開啟迴圈模式,那麼內部的播放引擎會呼叫客戶端程式設計師提供的OnCompletion.onCompletion()回撥方法。

可以通過呼叫MediaPlayer.setOnCompletionListener(OnCompletionListener)方法來設定。內部的播放引擎一旦調

用了OnCompletion.onCompletion()回撥方法,說明這個MediaPlayer物件進入了PlaybackCompleted狀態。

9.3) 當處於PlaybackCompleted狀態的時候,可以再呼叫start()方法來讓這個MediaPlayer物件再進入Started狀態。 

參考文獻:

1.谷歌官方Android SDK開發文件

2.http://my.oschina.net/zhangqingcai/blog/29660

相關文章