播放媒體的來源可以來自源文件、文件系統或網絡的數據流(URL)。
只能在標準的輸出設備上播放音頻,輸出設備指的是移動設備上揚聲器或藍牙耳機,不可以從電話的話筒播放音頻。一般而言,移動手機會有播放音樂用的揚聲器和通話用的話筒。
這裏我們主要使用MediaPlayer來實現音頻及視頻的播放功能。下面來介紹一下MediaPlayer的常用方法(表1)及監聽事件(表2)。
表1 MediaPlayer的常用方法
方法 | 描述 |
create(Context context, Uri uri) | 靜態方法,通過Uri創建一個多媒體播放器 |
create(Context context, int resid) | 靜態方法,通過資源ID創建一個多媒體播放器 |
create(Context context, Uri uri, SurfaceHolder holder) | 靜態方法,通過Uri和指定 SurfaceHolder 【抽象類】 創建一個多媒體播放器 |
getCurrentPosition() | 返回 Int, 得到當前播放位置 |
getDuration() | 返回 Int,得到文件的時間 |
getVideoHeight() | 返回 Int ,得到視頻的高度 |
getVideoWidth() | 返回 Int,得到視頻的寬度 |
isLooping() | 返回 boolean ,是否循環播放 |
isPlaying() | 返回 boolean,是否正在播放 |
pause() | 無返回值 ,暫停 |
prepare() | 無返回值,準備同步 |
prepareAsync() | 無返回值,準備異步 |
release() | 無返回值,釋放 MediaPlayer 對象 |
reset() | 無返回值,重置 MediaPlayer 對象 |
seekTo(int msec) | 無返回值,指定播放的位置(以毫秒爲單位的時間) |
setAudioStreamType(int streamtype) | 無返回值,指定流媒體的類型 |
setDataSource(String path) | 無返回值,設置多媒體數據來源【根據 路徑】 |
setDataSource(FileDescriptor fd, long offset, long length) | 無返回值,設置多媒體數據來源【根據 FileDescriptor】 |
setDataSource(FileDescriptor fd) | 無返回值,設置多媒體數據來源【根據 FileDescriptor】 |
setDataSource(Context context, Uri uri) | 無返回值,設置多媒體數據來源【根據 Uri】 |
setDisplay(SurfaceHolder sh) | 無返回值,設置用 SurfaceHolder 來顯示多媒體 |
setLooping(boolean looping) | 無返回值,設置是否循環播放 |
setScreenOnWhilePlaying(boolean screenOn) | 無返回值,設置是否使用 SurfaceHolder 顯示 |
setVolume(float leftVolume, float rightVolume) | 無返回值,設置音量 |
start() | 無返回值,開始播放 |
stop() | 無返回值,停止播放 |
表2 MediaPlayer的監聽事件
事件 | 描述 |
setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener) | 網絡流媒體的緩衝監聽 |
setOnCompletionListener(MediaPlayer.OnCompletionListener listener) | 網絡流媒體播放結束監聽 |
setOnErrorListener(MediaPlayer.OnErrorListener listener) | 設置錯誤信息監聽 |
setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener) | 視頻尺寸監聽 |
1 從源文件中播放
使用MediaPlayer類播放音頻及視頻,最簡單的一種方式就是從源文件中播放。要實現該功能需要以下步驟。
□ 將Android支持的媒體文件放在項目的res/raw文件夾下,如一個MP3文件,Eclipse開發環境的內置功能會發現這個文件,並將它生成一個信息,可以自R類引用到這個文件。
□ 創建一個MediaPlayer實例,可以使用MediaPlayer的靜態方法create來完成,讀出媒體資源。
□ 調用MediaPlayer實例的start()方法開始播放,調用stop()方法停止播放,調用pause()方法暫停播放,如暫停後再播放,需再次調用start()方法。如果希望重複播放,在調用start()方法之前,必須調用reset()和prepare()方法。
播放流程如圖8-1所示。
圖8-1 播放流程
程序代碼如代碼清單1所示。
代碼清單1 播放源文件中視頻或音頻方法
//實例化MediaPlayer
MediaPlayer mMediaPlayer = MediaPlayer.create(this,R.raw.test);
MediaPlayer//開始播放
MediaPlayermMediaPlayer.start();
由上述可知,從源文件中播放是放在“<工程>/res/raw”,然後發佈的時候被打成APK包一起安裝在手機上。很顯然這種方式不適合用於播放娛樂爲主的多媒體文件,由於娛樂的多媒體文件是經常更新的,而放置在這個raw下面的文件用戶是沒有權限更新的,因此這種方式一般用於應用自己的一些音頻和視頻播放,如按鍵音、開機啓動音、信息提示音等應用使用的聲音。
2 從文件系統中播放
從文件系統中播放也是比較常見的一種方式。例如,在SD卡中有一些音頻及視頻文件,那麼就可以直接進行播放。
從文件系統中播放需要以下步驟。
□ 實例化一個MediaPlayer。
□ 調用setDataSource()方法來設置想要播放文件的路徑,取得播放的媒體文件。
□ 首先調用prepare(),然後調用start()來進行播放。
播放流程如圖2所示。
圖2 從文件系統中播放音頻視頻的播放流程
程序代碼如代碼清單2所示。
代碼清單2 從文件系統中播放音頻或視頻
private void play() {
File sdCardDir = Environment.getExternalStorageDirectory();
//播放路徑
String path = sdCardDir.getPath() + “/Lover’s Concerto.mp3”;
try {
if (mMediaPlayer == null || state == STOP) {
// 創建MediaPlayer對象並設置Listener
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setOnPreparedListener(preListener);
} else {
// 複用MediaPlayer對象
mMediaPlayer.reset();
}
//爲MediaPlayer設置數據源
mMediaPlayer.setDataSource(path);
mMediaPlayer.prepare();
mMediaPlayer.start();
} catch (Exception e) {
e.printStackTrace();
}
}
從源文件中播放音頻視頻和從本地文件系統中播放音頻視頻的差別就在於play()方法中的mMediaPlayer = new MediaPlayer(),而不是MediaPlayer.Create(),然後設置預處理監聽器,設置setDataSource(path),其中的path是指定的音頻文件,這裏放置SD卡中的MP3文件,mMediaPlayer.prepare()開始預處理。
3 從網絡中播放
隨着3G的不斷完善和推廣,自費不斷降低,直接利用網絡資源已經不是什麼問題。移動互聯網時代已經到了。這裏就看一看如何通過網絡來播放音視頻文件。
要實現該功能有兩種方法。
1.方法一
□ 創建網絡URI實例。
□ 創建一個MediaPlayer實例,通過傳遞URI參數,使用MediaPlayer靜態方法create完成。
□ 調用start()方法開始播放。
程序代碼如代碼清單3所示。
代碼清單3從網絡中播放音頻或視頻方法一
private void play() {
try {
//播放路徑
String path =
"http://ms1.m.mop.com/2008/08/27/012/12198150127399164.mp3";
//將字符串Uri解析爲Uri實例
Uri uri = Uri.parse(path);
//實例化MediaPlayer
MediaPlayer player = MediaPlayer.create(this,uri);
//播放
player.start();
} catch (Exception e) {
e.printStackTrace();
}
}
2.方法二
□ 實例化一個MediaPlayer。
□ 調用setDataSource()方法來設置想要播放文件的路徑,該路徑是網絡上的可用路徑。
□ 首先調用prepare(),然後調用start()來進行播放。
程序代碼如代碼清單4所示。
代碼清單4 從網絡中播放音頻或視頻方法二
private void play() {
try {
//實例化MediaPlayer
MediaPlayer mp = new MediaPlayer();
//播放路徑
String path =
"http://ms1.m.mop.com/2008/08/27/012/12198150127399164.mp3";
try{
//設置數據源
mp.setDataSource(path);
//準備
mp.prepare();
//播放
mp.start();
}catch(IllegalArgumentException e){
e.printStackTrace();
}catch(IllegalStateException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
雖然從網絡中播放音頻視頻不用存儲比較方便,但它的弊端就是要通過網絡,速度要比從源文件中和從文件系統中播放兩種方式慢,因此上述兩種播放方式中,利用同步預處理方法prepare()播放網絡文件用戶體驗不好。一般網絡播放方式要採用異步預處理方式。還有網絡流量費用也會增加用戶的使用成本。
播放流程如圖3所示。
圖3 從網絡中播放音頻視頻流程圖
程序代碼如代碼清單5所示。
代碼清單5 從網絡中播放音頻或視頻——異步處理方式
private void play() {
try {
if (mMediaPlayer == null || state == STOP) {
// 創建MediaPlayer對象並設置Listener
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setOnPreparedListener(preListener);
} else {
// 複用MediaPlayer對象
mMediaPlayer.reset();
}
// 播放網絡媒體最好不要調用prepare()方法
mMediaPlayer
.setDataSource ("http://ms1.m.mop.com/2008/08/27/012/12198150127399164.mp3");
mMediaPlayer.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
}
}