android mediaplayer状态机
?
通過這張圖,我們可以知道一個(gè)MediaPlayer對(duì)象有以下的狀態(tài):
1.?當(dāng)一個(gè)MediaPlayer對(duì)象被剛剛用new操作符創(chuàng)建或是調(diào)用了reset()方法后,它就處于Idle狀態(tài)。當(dāng)調(diào)用了release()方法后,它就處于End狀態(tài)。這兩種狀態(tài)之間是MediaPlayer對(duì)象的生命周期。
??? 1)在一個(gè)新構(gòu)建的MediaPlayer對(duì)象和一個(gè)調(diào)用了reset()方法的MediaPlayer對(duì)象之間有一個(gè)微小的但是十分重要的差別。
? ? 在處于Idle狀態(tài)時(shí),調(diào)用getCurrentPosition(),?getDuration(),?getVideoHeight(),?getVideoWidth(),?setAudioStreamType(int),?setLooping(boolean),?setVolume(float, float),?pause(),?start(),?stop(),?seekTo(int),?prepare()?或者?prepareAsync()?方法都是編程錯(cuò)誤。
??? 當(dāng)一個(gè)MediaPlayer對(duì)象剛被構(gòu)建的時(shí)候,內(nèi)部的播放引擎和對(duì)象的狀態(tài)都沒有改變,在這個(gè)時(shí)候調(diào)用以上的那些方法,框架將無法回調(diào)客戶端程序注冊(cè)的OnErrorListener.onError()方法;
?????但若這個(gè)MediaPlayer對(duì)象調(diào)用了reset()方法之后,再調(diào)用以上的那些方法,內(nèi)部的播放引擎就會(huì)回調(diào)客戶端程序注冊(cè)的OnErrorListener.onError()方法了,并將錯(cuò)誤的狀態(tài)傳入。
??? 2) 建議一旦一個(gè)MediaPlayer對(duì)象不再被使用,應(yīng)立即調(diào)用release()方法來釋放在內(nèi)部的播放引擎中與這個(gè)MediaPlayer對(duì)象關(guān)聯(lián)的資源。
??????? 資源可能包括如硬件加速組件的單態(tài)組件,若沒有調(diào)用release()方法可能會(huì)導(dǎo)致之后的MediaPlayer對(duì)象實(shí)例無法使用這種單態(tài)硬件資源,從而退回到軟件實(shí)現(xiàn)或運(yùn)行失敗。一旦MediaPlayer對(duì)象進(jìn)入了End狀態(tài),它不能再被使用,也沒有辦法再遷移到其它狀態(tài)。
??? 3)此外,使用new操作符創(chuàng)建的MediaPlayer對(duì)象處于Idle狀態(tài),而那些通過重載的create()便利方法創(chuàng)建的MediaPlayer對(duì)象卻不是處于Idle狀態(tài)。事實(shí)上,如果成功調(diào)用了重載的create()方法,那么這些對(duì)象已經(jīng)是Prepare狀態(tài)了。?
2.?在一般情況下,由于種種原因一些播放控制操作可能會(huì)失敗,如不支持的音頻/視頻格式,缺少隔行掃描的音頻/視頻,分辨率太高,流超時(shí)等原因,等等。因此,錯(cuò)誤報(bào)告和恢復(fù)在這種情況下是非常重要的。有時(shí),由于編程錯(cuò)誤,在處于無效狀態(tài)的情況下調(diào)用了一個(gè)播放控制操作可能發(fā)生。在所有這些錯(cuò)誤條件下,內(nèi)部的播放引擎會(huì)調(diào)用一個(gè)由客戶端程序員提供的OnErrorListener.onError()方法??蛻舳顺绦騿T可以通過調(diào)用MediaPlayer.setOnErrorListener(android.media.MediaPlayer.OnErrorListener)方法來注冊(cè)O(shè)nErrorListener.
??? 1)一旦發(fā)生錯(cuò)誤,MediaPlayer對(duì)象會(huì)進(jìn)入到Error狀態(tài)。
??? 2) 為了重用一個(gè)處于Error狀態(tài)的MediaPlayer對(duì)象,可以調(diào)用reset()方法來把這個(gè)對(duì)象恢復(fù)成Idle狀態(tài)。
??? 3) 注冊(cè)一個(gè)OnErrorListener來獲知內(nèi)部播放引擎發(fā)生的錯(cuò)誤是好的編程習(xí)慣。
??? 4) 在不合法的狀態(tài)下調(diào)用一些方法,如prepare(),prepareAsync()和setDataSource()方法會(huì)拋出IllegalStateException異常。?
3.?調(diào)用setDataSource(FileDescriptor)方法,或setDataSource(String)方法,或setDataSource(Context,Uri)方法,或setDataSource(FileDescriptor,long,long)方法會(huì)使處于Idle狀態(tài)的對(duì)象遷移到Initialized狀態(tài)。
??? 1) 若當(dāng)此MediaPlayer處于其它的狀態(tài)下,調(diào)用setDataSource()方法,會(huì)拋出IllegalStateException異常。
??? 2) 好的編程習(xí)慣是不要疏忽了調(diào)用setDataSource()方法的時(shí)候可能會(huì)拋出的IllegalArgumentException異常和IOException異常。?
4.?在開始播放之前,MediaPlayer對(duì)象必須要進(jìn)入Prepared狀態(tài)。
??? 1) 有兩種方法(同步和異步)可以使MediaPlayer對(duì)象進(jìn)入Prepared狀態(tài):
??? 第一種是調(diào)用prepare()方法(同步),此方法返回就表示該MediaPlayer對(duì)象已經(jīng)進(jìn)入了Prepared狀態(tài);
??? 第二種是調(diào)用prepareAsync()方法(異步),此方法會(huì)使此MediaPlayer對(duì)象進(jìn)入Preparing狀態(tài)并返回,而內(nèi)部的播放引擎會(huì)繼續(xù)未完成的準(zhǔn)備工作。當(dāng)同步版本返回時(shí)或異步版本的準(zhǔn)備工作完全完成時(shí)就會(huì)調(diào)用客戶端程序員提供的OnPreparedListener.onPrepared()監(jiān)聽方法??梢哉{(diào)用MediaPlayer.setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener)方法來注冊(cè)OnPreparedListener.
??? 2)?Preparing是一個(gè)中間狀態(tài),在此狀態(tài)下調(diào)用任何具備邊影響的方法的結(jié)果都是未知的!
??? 3) 在不合適的狀態(tài)下調(diào)用prepare()和prepareAsync()方法會(huì)拋出IllegalStateException異常。當(dāng)MediaPlayer對(duì)象處于Prepared狀態(tài)的時(shí)候,可以調(diào)整音頻/視頻的屬性,如音量,播放時(shí)是否一直亮屏,循環(huán)播放等。?
5.?要開始播放,必須調(diào)用start()方法。當(dāng)此方法成功返回時(shí),MediaPlayer的對(duì)象處于Started狀態(tài)。isPlaying()方法可以被調(diào)用來測試某個(gè)MediaPlayer對(duì)象是否在Started狀態(tài)。
???? 1) 當(dāng)處于Started狀態(tài)時(shí),內(nèi)部播放引擎會(huì)調(diào)用客戶端程序員提供的OnBufferingUpdateListener.onBufferingUpdate()回調(diào)方法,此回調(diào)方法允許應(yīng)用程序追蹤流播放的緩沖的狀態(tài)。
??? 2) 對(duì)一個(gè)已經(jīng)處于Started?狀態(tài)的MediaPlayer對(duì)象調(diào)用start()方法沒有影響。
6.?播放可以被暫停,停止,以及調(diào)整當(dāng)前播放位置。當(dāng)調(diào)用pause()方法并返回時(shí),會(huì)使MediaPlayer對(duì)象進(jìn)入Paused狀態(tài)。注意Started與Paused狀態(tài)的相互轉(zhuǎn)換在內(nèi)部的播放引擎中是異步的。所以可能需要一點(diǎn)時(shí)間在isPlaying()方法中更新狀態(tài),若在播放流內(nèi)容,這段時(shí)間可能會(huì)有幾秒鐘。
??? 1) 調(diào)用start()方法會(huì)讓一個(gè)處于Paused狀態(tài)的MediaPlayer對(duì)象從之前暫停的地方恢復(fù)播放。當(dāng)調(diào)用start()方法返回的時(shí)候,MediaPlayer對(duì)象的狀態(tài)會(huì)又變成Started狀態(tài)。
??? 2) 對(duì)一個(gè)已經(jīng)處于Paused狀態(tài)的MediaPlayer對(duì)象pause()方法沒有影響。
7.?調(diào)用stop()方法會(huì)停止播放,并且還會(huì)讓一個(gè)處于Started,Paused,Prepared或PlaybackCompleted狀態(tài)的MediaPlayer進(jìn)入Stopped狀態(tài)。
??? 對(duì)一個(gè)已經(jīng)處于Stopped狀態(tài)的MediaPlayer對(duì)象stop()方法沒有影響。
8.?調(diào)用seekTo()方法可以調(diào)整播放的位置。
????1)?seekTo(int)方法是異步執(zhí)行的,所以它可以馬上返回,但是實(shí)際的定位播放操作可能需要一段時(shí)間才能完成,尤其是播放流形式的音頻/視頻。當(dāng)實(shí)際的定位播放操作完成之后,內(nèi)部的播放引擎會(huì)調(diào)用客戶端程序員提供的OnSeekComplete.onSeekComplete()回調(diào)方法??梢酝ㄟ^setOnSeekCompleteListener(OnSeekCompleteListener)方法注冊(cè)。
??? 2) 注意,seekTo(int)方法也可以在其它狀態(tài)下調(diào)用,比如Prepared,Paused和PlaybackCompleted狀態(tài)。此外,目前的播放位置,實(shí)際可以調(diào)用getCurrentPosition()方法得到,它可以幫助如音樂播放器的應(yīng)用程序不斷更新播放進(jìn)度
9.?當(dāng)播放到流的末尾,播放就完成了。
??? 1) 如果調(diào)用了setLooping(boolean)方法開啟了循環(huán)模式,那么這個(gè)MediaPlayer對(duì)象會(huì)重新進(jìn)入Started狀態(tài)。
??? 2) 若沒有開啟循環(huán)模式,那么內(nèi)部的播放引擎會(huì)調(diào)用客戶端程序員提供的OnCompletion.onCompletion()回調(diào)方法。可以通過調(diào)用MediaPlayer.setOnCompletionListener(OnCompletionListener)方法來設(shè)置。內(nèi)部的播放引擎一旦調(diào)用了OnCompletion.onCompletion()回調(diào)方法,說明這個(gè)MediaPlayer對(duì)象進(jìn)入了PlaybackCompleted狀態(tài)。
??? 3) 當(dāng)處于PlaybackCompleted狀態(tài)的時(shí)候,可以再調(diào)用start()方法來讓這個(gè)MediaPlayer對(duì)象再進(jìn)入Started狀態(tài)。
總結(jié)
以上是生活随笔為你收集整理的android mediaplayer状态机的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。