本文鏈接: "Android MediaPlayer 基礎簡介" 簡單介紹MediaPlayer的基本概念,狀態,常用的方法與監聽器。 什麼是MediaPlayer MediaPlayer類可以用來播放音視頻文件,或者是音頻流。開發者可以用它來播放本地音頻,或者是網路線上音頻。 MediaPlaye ...
本文鏈接: Android MediaPlayer 基礎簡介
簡單介紹MediaPlayer的基本概念,狀態,常用的方法與監聽器。
什麼是MediaPlayer
MediaPlayer類可以用來播放音視頻文件,或者是音頻流。開發者可以用它來播放本地音頻,或者是網路線上音頻。
MediaPlayer屬於android.media
包。
MediaPlayer的狀態
播放控制由狀態機控制。在日常生活中,我們常見的音頻狀態有播放中,暫停,停止,緩衝等等。
MediaPlayer的狀態有如下幾種:
- Idle
- End
- Error
- Initialized
- Preparing
- Prepared
- Started
- Stopped
- Paused
- PlaybackCompleted
狀態的切換參考官方圖例。
這裡稍微解釋一下狀態轉換圖片。橢圓代表MediaPlayer可能停留的狀態。橢圓之間的箭頭表示方法調用,狀態切換的方向。單箭頭表示方法同步調用,雙箭頭表示非同步調用。
從圖中我們可以看出狀態切換的路徑和涉及到的方法。
Idle與End狀態
當new一個MediaPlayer或者調用了reset方法,當前MediaPlayer會處於Idle狀態。調用release後,會處於End狀態。在這2個狀態之間的狀態可以看做是MediaPlayer對象的生命周期。
在新創建MediaPlayer和調用reset的MediaPlayer之間有一些細微的差別。
這兩種情況都處於Idle狀態,調用 getCurrentPosition(), getDuration(), getVideoHeight(), getVideoWidth(), setAudioAttributes(android.media.AudioAttributes), setLooping(boolean), setVolume(float, float), pause(), start(), stop(), seekTo(long, int), prepare() 或 prepareAsync()方法都會拋出錯誤,如果是新實例化的MediaPlayer,不會回調 OnErrorListener.onError();但如果是reset後的MediaPlayer,會回調 OnErrorListener.onError()並且轉換到Error狀態。
如果MediaPlayer對象不再使用了,立即調用release()方法,釋放內部播放器占用的資源。這些資源可能是唯一的,比如硬體加速組件。如果調用release失敗,可能會引起一連串的MediaPlayer實例失效。當MediaPlayer處於End狀態,它就不能再轉移到其它狀態了。
new一個MediaPlayer,處於Idle狀態。如果用create方法創建實例,當創建完成時處於Prepared狀態。
發生錯誤
一些情形可能會讓MediaPlayer操作失敗,比如不支持的音視頻格式,解析度過高,網路超時等等。
因此在這些情形下錯誤處理和恢復非常重要。有時候編程錯誤也會導致MediaPlayer操作錯誤。
開發者可以設置錯誤監聽器setOnErrorListener(android.media.MediaPlayer.OnErrorListener)
。當錯誤發生時,會調用用戶實現的OnErrorListener.onError()方法。
不管有沒有設置監聽器,錯誤發生時MediaPlayer會進入Error狀態。
為了重覆使用同一個MediaPlayer對象,可以使用reset()
方法把它從Error狀態恢復到Idle狀態。
設置錯誤監聽器OnErrorListener是一個好的編程習慣。開發者可以監聽到播放引擎的錯誤通知。
有時候會拋出IllegalStateException異常,比如在錯誤的狀態調用了prepare(), prepareAsync()方法,或是setDataSource方法。
設置音源 setDataSource
調用setDataSource(java.io.FileDescriptor), 或者 setDataSource(java.lang.String), 或者 setDataSource(android.content.Context, android.net.Uri), 或者 setDataSource(java.io.FileDescriptor, long, long), 或者 setDataSource(android.media.MediaDataSource) 可以將MediaPlayer的狀態從Idle轉到Initialized狀態。
如果在Idle狀態之外的狀態調用了setDataSource(),會拋出IllegalStateException異常。
開發者應該留意setDataSource方法拋出的IllegalArgumentException和IOException異常。
播放音頻前必須在Prepared狀態
MediaPlayer在開始播放音頻前必須處於Prepared狀態。
MediaPlayer有同步和非同步2種方式來進入Prepared狀態。如果是非同步的方式,會先轉到Preparing狀態,再轉到Prepared狀態。
當準備完成時,內部的播放引擎會回調用戶之前設置的OnPreparedListener的onPrepared()方法。
開發者必須註意的是,Preparing狀態是一個過渡狀態(transient state)。
處於Prepared狀態時,可以通過相對應的方法設置音量,屏幕常亮,播放迴圈等。
開始播放
播放音頻必須調用start()方法。調用start()返回成功後,MediaPlayer處於Started狀態。
可以通過isPlaying()來判斷當前是否在Started狀態。
如果開發者設置了OnBufferingUpdateListener,Android內部播放器會向外傳遞buffer信息。
如果當前處於Started狀態,再調用start()方法沒有效果。
暫停播放與繼續播放
音頻可以被暫停播放和繼續播放,也可以調整播放的位置。通過pause()方法來暫停音頻播放。
成功調用pause()方法後,MediaPlayer進入Paused狀態。
應當註意的是,MediaPlayer在Started狀態與Paused狀態之間切換是非同步的。播放音頻流的時候,這個轉換過程可能會需要幾秒鐘。
MediaPlayer暫停時,start()方法可以從暫停的位置繼續播放。成功調用start方法後會進入Started狀態。
處於Paused狀態時,調用pause()方法沒有效果。
停止
調用stop()方法讓MediaPlayer從Started, Paused, Prepared 或 PlaybackCompleted 狀態進入 Stopped 狀態。
在Stopped狀態時,必須先調用prepare() 或 prepareAsync()進入Prepared狀態後,才能播放音頻。
處於Stopped狀態時,調用stop()方法沒有效果。
調整播放位置
調用seekTo(long, int)來調整播放位置。
seekTo(long, int)是一個非同步方法,雖然它能立刻返回,但實際的位置調整可能會消耗一段時間,特別是在播放音頻流的時候。當實際播放位置調整後,內部播放器會回調開發者設置的OnSeekComplete.onSeekComplete()。
在Prepared, Paused 和 PlaybackCompleted狀態中,都可以調用seekTo方法。
可以通過getCurrentPosition()方法來獲取當前播放位置。開發者可以得知當前播放的進度等等。
播放完畢
音頻播放完成後,播放完畢。
如果調用setLooping(boolean)為true,MediaPlayer會停留在Started狀態。
如果setLooping為false,內部播放器會調用開發者設置的OnCompletion.onCompletion(),並且進入PlaybackCompleted狀態。
處於PlaybackCompleted狀態時,調用start()方法可以從頭開始播放音頻。
常用監聽器
開發者可以設置一些監聽器,監聽MediaPlayer的狀態,錯誤事件等等。開發者應在同一個線程中創建MediaPlayer與設置的監聽器。
setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener)
監聽MediaPlayer準備完成。一般與prepareAsync
配合使用。
setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener)
獲知video大小或video大小改變時的監聽。
setOnSeekCompleteListener(android.media.MediaPlayer.OnSeekCompleteListener)
監聽調整位置完成。
setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener)
播放完成。
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
// 當前播放完畢
}
});
setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener)
監聽緩衝進度。在播放網路音頻時常用。
緩衝監聽器OnBufferingUpdateListener
mMediaPlayer.prepareAsync();
mMediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
// 例如在這裡更新UI
}
});
setOnInfoListener(android.media.MediaPlayer.OnInfoListener)
監聽普通信息或者警告信息。
setOnErrorListener(android.media.MediaPlayer.OnErrorListener)
監聽錯誤信息。錯誤發生時,可以在這裡處理錯誤。
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
LogUtil.e(TAG_PREFIX + " onERR i = " + i + " i1 = " + i1);
return true; // 返回true表示在此處理錯誤,不會回調onCompletion
}
});
註意onError的返回值。可以選擇自己處理error。
* @return True if the method handled the error, false if it didn't.
* Returning false, or not having an OnErrorListener at all, will
* cause the OnCompletionListener to be called.
*/
boolean onError(MediaPlayer mp, int what, int extra);
需要的許可權
播放網路音頻時需要Manifest.permission.INTERNET許可權。