1、MediaPlayer的生命周期
有兩種類型的弧,單箭頭表示的是同步方法調(diào)用,有兩個箭頭代表異步方法調(diào)用
1、Idle 狀態(tài)及End 狀態(tài)
當使用new()方法創(chuàng)建一個MediaPlayer對象或者調(diào)用了其reset()方法時,該MediaPlayer對象處于idle狀態(tài)。release()方法調(diào)用后進入End狀態(tài)。
2、Initialized 狀態(tài)
setDataSource()調(diào)用之后,MediaPlayer就進入Initialized狀態(tài),表示要播放的文件已經(jīng)設置好了。如果setDataSource()在MediaPlayer的非Idle 狀態(tài)調(diào)用,會拋出IllegalStateException異常
3、Prepared狀態(tài)
MediaPlayer準備好了
- prepare():同步方法,調(diào)用這個方法,MediaPlayer就進入Prepared狀態(tài)
- prepareAsync():異步方法,經(jīng)過Preparing 狀態(tài),在準備工作結束之后,進入Prepared狀態(tài),會回調(diào)OnPreparedListener.onPrepared()。
在Prepared狀態(tài)之后,就可以調(diào)用MediaPlayer的一些set方法了,如,setScreenOnWhilePlaying()、setVolume()、setLooping()。
4、Started 狀態(tài),Paused 狀態(tài)
在MediaPlayer準備好之后,調(diào)用start()方法,此時MediaPlayer就處于Started狀態(tài);調(diào)用pause()方法,MediaPlayer進入Paused狀態(tài)。
如果注冊過OnBufferingUpdateListener,在Started 狀態(tài)時,MediaPlayer就會回調(diào)onBufferingUpdate()方法,可以使應用程序保持跟蹤視頻流的緩沖
5、Stopped 狀態(tài)
當MediaPlayer處于Started 、Paused 、Prepared、PlaybackCompleted狀態(tài)下,均可調(diào)用stop()停止MediaPlayer,而處于Stopped狀態(tài)的MediaPlayer要想重新播放,需要通過prepareAsync()(prepare())方法回到Prepared狀態(tài)才可以。
6、PlaybackCompleted狀態(tài)
文件正常播放完畢,而又沒有設置循環(huán)播放的話就進入該狀態(tài),并會觸發(fā)OnCompletionListener的onCompletion()方法。
7、Error 狀態(tài)
如果由于某種原因MediaPlayer出現(xiàn)了錯誤,會觸發(fā)OnErrorListener.onError()事件,此時MediaPlayer即進入Error狀態(tài)
注意:
1、MediaPlayer會消耗系統(tǒng)的資源,需要在適當?shù)臅r候把不需要的資源釋放掉。例如,如果在Activity中調(diào)用onStop()方法時,需要釋放MediaPlayer。當Activity恢復或者重新啟動時,需要創(chuàng)建一個新的MediaPlayer并且重新準備。
釋放MediaPlayer
mediaPlayer.release();
mediaPlayer = null;
2、SurfaceView
SurfaceView是配合MediaPlayer,將一幀一幀的圖像,顯示在界面上。
指定MediaPlayer顯示圖像
void setDisplay(SurfaceHolder holder)
- SurfaceHolder可以理解為SurfaceView裝載需要顯示的一幀幀圖像的容器,它可以通過SurfaceHolder.getHolder()方法獲得。
- SurfaceView,通過雙緩沖的機制來顯示幀圖像。雙緩沖可以理解為有兩個線程輪番去 解析視頻流的幀圖像,當一個線程解析完幀圖像后,把圖像渲染到界面中,同時另一線程開始解析下一幀圖像,使得兩個線程輪番配合去解析視頻流,以達到流暢播放的效果。
- SurfaceView內(nèi)部實現(xiàn)了雙緩沖的機制,但是實現(xiàn)這個功能是非常消耗系統(tǒng)內(nèi)存的。因為移動設備的局限性,Android在設計的時候規(guī) 定,SurfaceView如果為用戶可見的時候,創(chuàng)建SurfaceView的SurfaceHolder用于顯示視頻流解析的幀圖片,如果發(fā)現(xiàn) SurfaceView變?yōu)橛脩舨豢梢姷臅r候,則立即銷毀SurfaceView的SurfaceHolder,以達到節(jié)約系統(tǒng)資源的目的。所以,需要去維護一個SurfaceHolder,需要用到它的一個回調(diào),SurfaceHolder.Callback()
public interface Callback {
public void surfaceCreated(SurfaceHolder holder);
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height);
public void surfaceDestroyed(SurfaceHolder holder);
}
3、使用
/**
* todo public
* 加載視頻
*/
public void loadAndPlay(String videoUrl){
this.videoUrl=videoUrl;
surfaceView.getHolder().setKeepScreenOn(true);
surfaceView.getHolder().addCallback(new SurfaceViewCallback());
}
/**
* 當用戶不可見的時候 ,SurfaceHolder 就會銷毀,當再次可見的時候,會創(chuàng)建新的SurfaceHolder;
* 使用SurfaceHolder.Callback()維護一個SurfaceHolder
*/
class SurfaceViewCallback implements SurfaceHolder.Callback {
@Override
public void surfaceCreated(SurfaceHolder holder) {
if(mediaPlayer==null){
mediaPlayer=new MediaPlayer();
mediaPlayer.setDataSource(videoUrl);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setOnCompletionListener(new MediaPlayerCompletion());
mediaPlayer.prepareAsync();
mediaPlayer.setDisplay(surfaceView.getHolder());
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isVideoPrepared=false;
if(mediaPlayer!=null){
mediaPlayer.release();
mediaPlayer=null;
}
}
}
/**
* 視頻準備好回調(diào)
*/
@Override
public void onPrepared(MediaPlayer mp) {
isVideoPrepared=true;
mediaPlayer.start();
mediaPlayer.setScreenOnWhilePlaying(true);
}
private boolean isVideoPrepared;
Android Multimedia框架總結(一)MediaPlayer介紹之狀態(tài)圖及生命周期、Android Multimedia框架總結(三)MediaPlayer中創(chuàng)建到setDataSource過程