上一篇說到音頻錄制的時候我就知道肯定會有音頻播放這個功能,果不其然后續(xù)播放的需求又給我加上了掂林,因為之前是AMR格式进宝,所以這里使用MediaPlayer進行播放恨搓,據(jù)ios說播放amr格式的音頻還挺麻煩的部逮。
一、添加必要權限
//有播放網(wǎng)絡資源的需要添加網(wǎng)絡權限嫂易。
<uses-permission android:name="android.permission.INTERNET"/>
//播放本地資源需要添加SD卡權限兄朋,一般存儲我都會全加上。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
//在播放時有特殊設置的需要聲明一個相應的WAKE_LOCK權限
<uses-permission android:name="android.permission.WAKE_LOCK"/>
二、MediaPlayer 介紹
1.狀態(tài)圖
音頻/視頻文件和流的播放控制作為狀態(tài)機進行管理颅和。下圖顯示了受支持的播放控制操作驅動的 MediaPlayer 對象的生命周期和狀態(tài)傅事。橢圓形表示 MediaPlayer 對象可能駐留的狀態(tài)∠坷弧形表示驅動對象狀態(tài)轉換的回放控制操作蹭越。有兩種類型的弧。具有單箭頭的弧表示同步方法調(diào)用教届,而具有雙箭頭的弧表示異步方法調(diào)用响鹃。
具體信息可以去Android官網(wǎng)閱讀
2.MediaPlayer公開方法
方法有很多,這里只說常用的幾個方法案训,其他的去Android官網(wǎng)查閱买置。
公開方法 | |
---|---|
static MediaPlayer | create(Context context, int resid )為給定資源ID創(chuàng)建MediaPlayer的便捷方法,一般播放Raw下資源會使用此方法强霎。 |
void | setDataSource (AssetFileDescriptor afd) setDataSource (FileDescriptor fd) setDataSource (String path) setDataSource (MediaDataSource dataSource) setDataSource (Context context, Uri uri) 設置數(shù)據(jù)源忿项,這里可以設置 AssetFileDescriptor 、 FileDescriptor 城舞、 文件路徑或http / rtsp URL 轩触、 MediaDataSource 、 Uri |
void | prepare() 同步準備播放器以進行播放家夺。 |
void | prepareAsync() 準備播放器異步播放脱柱。 |
void | pause() 暫停播放。 |
void | release() 釋放與此MediaPlayer對象關聯(lián)的資源秦踪。 |
void | reset() 將MediaPlayer重置為其未初始化狀態(tài)褐捻。 |
void | start() 開始或繼續(xù)播放。 |
void | stop() 開始或暫停播放后停止播放椅邓。 |
void | setVolume(float leftVolume, float rightVolume) 設置播放的音量柠逞,左右聲道取值 0~1。 |
void | setOnCompletionListener(MediaPlayer. OnCompletionListener listener) 播放完成后的回調(diào)景馁。 |
void | setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener) 網(wǎng)絡流緩沖區(qū)的狀態(tài)更改時的回調(diào)板壮。 |
void | setOnErrorListener(MediaPlayer.OnErrorListener listener) 錯誤回調(diào)。 |
void | setOnInfoListener(MediaPlayer.OnInfoListener listener) 注冊一個在信息/警告可用時要調(diào)用的回調(diào)合住。 |
void | setOnPreparedListener(MediaPlayer.OnPreparedListener listener) 注冊當媒體源準備好播放時要調(diào)用的回調(diào)绰精。 |
void | setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener) 指定播放位置后的回調(diào)。 |
boolean | isLooping() 檢查MediaPlayer是循環(huán)還是非循環(huán)透葛。 |
boolean | isPlaying() 檢查MediaPlayer是否正在播放笨使。 |
void | seekTo(long msec) 播放指定的時間位置。 |
void | setScreenOnWhilePlaying(boolean screenOn) 控制在播放時是否熄屏僚害。 |
三硫椰、代碼編寫
這里有個需要注意的地方:一般加載比較小的資源時候可以使用prepare(),但是如果你加載資源比較大的或者是網(wǎng)絡資源的時候就是一個耗時操作,我們都知道不能在主線程執(zhí)行耗時操作靶草,所以就需要使用prepareAsync()配合setOnPreparedListener()在準備完成后自動播放音頻蹄胰。
如果你不信這個邪你可以用prepare()加載網(wǎng)絡資源試試。
/**
* 設置播放類型奕翔,之后調(diào)用stop方便切換類型裕寨。
*/
private int PLAY_STATE = -1;//判斷是什么類型
public static final int PLAY_STATE0 = 1;//文件
public static final int PLAY_STATE1 = 2;//raw
public static final int PLAY_STATE2 = 3;//assets
public static final int PLAY_STATE3 = 4;//網(wǎng)絡
private MediaPlayer mMediaPlayer = null;
//設置不同的回調(diào)
private MediaPlayFunctionListener mediaPlayFunctionListener;
private MediaPlayInfoListener mMediaPlayInfoListener;
//設置文件路徑
public void setFilePlay(File file) {
this.targetFile = file;
PLAY_STATE = PLAY_STATE0;
stop();
}
//設置Raw播放
public void setRawPlay(Context context,int rawId){
this.mContext = context;
this.rawId = rawId;
PLAY_STATE = PLAY_STATE1;
stop();
}
//設置Assets播放
public void setAssetsName(Context context,String assetsName) {
this.mContext = context;
this.assetsName = assetsName;
PLAY_STATE = PLAY_STATE2;
stop();
}
//設置網(wǎng)絡資源播放
public void setNetPath(String netPath) {
this.netPath = netPath;
PLAY_STATE = PLAY_STATE3;
stop();
}
//開始播放
public boolean start() {
if (PLAY_STATE == PLAY_STATE1){
mMediaPlayer = MediaPlayer.create(mContext,rawId);
}else {
mMediaPlayer = new MediaPlayer();
}
try {
switch (PLAY_STATE){
case PLAY_STATE0://本地文件為數(shù)據(jù)源傳入路徑
mMediaPlayer.setDataSource(targetFile.getAbsolutePath());
mMediaPlayer.prepare();
break;
case PLAY_STATE1://如果raw為數(shù)據(jù)源則不處理
break;
case PLAY_STATE2://Assets下文件為數(shù)據(jù)源
AssetFileDescriptor fileDescriptor = mContext.getAssets().openFd(assetsName);
mMediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),fileDescriptor.getStartOffset(),fileDescriptor.getLength());
mMediaPlayer.prepare();
break;
case PLAY_STATE3://網(wǎng)絡數(shù)據(jù)源 設置網(wǎng)絡連接
mMediaPlayer.setDataSource(netPath);
mMediaPlayer.prepareAsync();
break;
}
//播放完成自動停止
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override public void onCompletion(MediaPlayer mediaPlayer) {
//停止播放
mediaPlayer.stop();
//回調(diào)停止播放的方法。
if (mediaPlayFunctionListener != null)
mediaPlayFunctionListener.stop();
//回調(diào)播放完成的方法
if (mMediaPlayInfoListener != null)
mMediaPlayInfoListener.onCompletion(mediaPlayer);
}
});
//準備完畢 自動播放
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
//準備完畢派继,回調(diào)準備和開始方法
if (mediaPlayFunctionListener != null) {
mediaPlayFunctionListener.prepared();
mediaPlayFunctionListener.start();
}
}
});
//播放錯誤監(jiān)聽
mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override public boolean onError(MediaPlayer mp, int what, int extra) {
//回調(diào)錯誤方法
if (mMediaPlayInfoListener != null) {
mMediaPlayInfoListener.onError(mp, what, extra);
}
//回調(diào)停止方法
if (mMediaPlayer != null)
stop();
return false;
}
});
//網(wǎng)絡緩沖監(jiān)聽
mMediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
@Override public void onBufferingUpdate(MediaPlayer mp, int percent) {
//回調(diào)網(wǎng)絡緩沖方法
if (mMediaPlayInfoListener != null)
mMediaPlayInfoListener.onBufferingUpdate(mp,percent);
}
});
//調(diào)整進度監(jiān)聽
mMediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
@Override public void onSeekComplete(MediaPlayer mp) {
//回調(diào)調(diào)整進度后的方法宾袜,這里只有調(diào)整播放位置后才會調(diào)用
if (mMediaPlayInfoListener != null)
mMediaPlayInfoListener.onSeekComplete(mp);
}
});
} catch (IOException e) {
e.printStackTrace();
mMediaPlayer.stop();
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
}
boolean result = (mMediaPlayer != null);
this.isPlaying = result;
return result;
}
//停止播放
public void stop() {
this.isPlaying = false;
this.duration = 0;
if (mMediaPlayer != null) {
mHandler.removeCallbacks(mRunnable);
mMediaPlayer.stop();
mMediaPlayer.reset();
if (mediaPlayFunctionListener != null)
mediaPlayFunctionListener.reset();
mMediaPlayer.release();
mMediaPlayer = null;
}
}
//resume調(diào)用 繼續(xù)播放也調(diào)用此方法即可
public void resume() {
if (mMediaPlayer != null) {
this.isPlaying = true;
mHandler.postDelayed(mRunnable,sleep);
mMediaPlayer.start();
}
}
//暫停
public void pause() {
this.isPlaying = false;
mHandler.removeCallbacks(mRunnable);
if (mMediaPlayer != null) {
mMediaPlayer.pause();
if (mediaPlayFunctionListener != null)
mediaPlayFunctionListener.pause();
}
}
我已經(jīng)把MediaPlayer寫成工具類上傳到Github中具體的使用方法可以查看Wiki,如果你想直接使用導入依賴即可互艾,如果你不想去Github想直接修改或者自定義其他方法直接下載 mediaplaylib (提取碼: xnv5) 即可