MediaPlayer加载不同的资源文件 重复播放
MediaPlayer加载不同的资源文件 重复播放
需求是这样,有许多本地的声音文件,放在raw资源文件内,点击不同的按钮会调用不同的声音播放。并且如果在上一次声音没有播放完成之前就点击另外一个按钮,则会中断之前的播放,直接播放当前的声音文件。
关于MediaPlayer的加载方法有以下几种:
如何设置要播放的文件:
MediaPlayer要播放的文件主要包括3个来源:
a. 用户在应用中事先自带的resource资源
例如:MediaPlayer.create(this, R.raw.test);
b. 存储在SD卡或其他文件路径下的媒体文件
例如:mp.setDataSource("/sdcard/test.mp3");
c. 网络上的媒体文件
例如:mp.setDataSource("http://www.citynorth.cn/music/confucius.mp3");
我们是选择资源文件,所以使用第一种方法。
根据阅读MediaPlayer的源码,得知用此种方法每次都要new 一个MediaPlayer对象,这样效率很低下
以下是系统创建MediaPlayer 的方法:
public static MediaPlayer create(Context context, int resid,
AudioAttributes audioAttributes, int audioSessionId) {
try {
AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid);
if (afd == null) return null;
MediaPlayer mp = new MediaPlayer();
final AudioAttributes aa = audioAttributes != null ? audioAttributes :
new AudioAttributes.Builder().build();
mp.setAudioAttributes(aa);
mp.setAudioSessionId(audioSessionId);
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
mp.prepare();
return mp;
} catch (IOException ex) {
Log.d(TAG, "create failed:", ex);
// fall through
} catch (IllegalArgumentException ex) {
Log.d(TAG, "create failed:", ex);
// fall through
} catch (SecurityException ex) {
Log.d(TAG, "create failed:", ex);
// fall through
}
return null;
}
看到核心创建代码为
AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid);
if (afd == null) return null;
MediaPlayer mp = new MediaPlayer();
final AudioAttributes aa = audioAttributes != null ? audioAttributes :
new AudioAttributes.Builder().build();
mp.setAudioAttributes(aa);
mp.setAudioSessionId(audioSessionId);
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
于是想到复写这个方法,因为Mediaplayer已经创建 ,所以在第二次设置时不需要设置AudioAttributers,可以直接根据资源文件,调用setDataSource方法:
public static MediaPlayer getMediaPlayer(Context context, int resid) {
AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid);
if (afd == null) return null;
if (null == mMediaPlayer) {
mMediaPlayer = MediaPlayer.create(context, resid);
mMediaPlayer.setOnCompletionListener(mListener);
mMediaPlayer.setOnErrorListener(mErroListener);
return mMediaPlayer;
}
try {
mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
mMediaPlayer.prepare();
mMediaPlayer.setOnCompletionListener(mListener);
mMediaPlayer.setOnErrorListener(mErroListener);
return mMediaPlayer;
} catch (IOException ex) {
// fall through
} catch (IllegalArgumentException ex) {
// fall through
} catch (SecurityException ex) {
// fall through
}
return null;
}
可是这种方法依然不行,系统会抛出异常,查阅资料是因为再次调用的时候,C++底层认为这个Player和之前的ID不一样所以抛出异常,此时如果调用isPlaying方法也会报出同样的错误,所以还是用了最进本的方法,每次创建一个MediaPlayer,用完后release掉:
public class SoundManagerUtil {
private static MediaPlayer mMediaPlayer;
private static MediaPlayer.OnCompletionListener mListener = new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
stopAndReleaseMeiaPlayer();
}
};
private static MediaPlayer.OnErrorListener mErroListener = new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mMediaPlayer.reset();
return false;
}
};
private static void stopAndReleaseMeiaPlayer() {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
}
public static void sendSound(Context context, int soundName) {
if (null == mMediaPlayer) {
getmMediaPlayerByName(context, soundName);
} else {
//mediaplayer对象的状态和native的对象状态发生了不一致
try {
if (mMediaPlayer.isPlaying()) {
stopAndReleaseMeiaPlayer();
}
} catch (Exception e) {
}
}
getmMediaPlayerByName(context, soundName);
if (null == mMediaPlayer) {
Log.e("kevin", "cant find soundName");
return;
}
mMediaPlayer.start();
}
public static void getmMediaPlayerByName(Context context, int soundName) {
switch (soundName) {
case Constance.BANK_CARD_RESERVATION_PHONE_NUMBER:
mMediaPlayer = getMediaPlayer(context, R.raw.bank_card_reservation_phone_number_tips);
break;
case Constance.BORROW_ENTER_PHONE_NUMBER:
mMediaPlayer = getMediaPlayer(context, R.raw.borrow_enter_phone_number);
break;
case Constance.BORROWING_QUOTA:
mMediaPlayer = getMediaPlayer(context, R.raw.borrowing_quota);
break;
case Constance.ENTER_PHONE_NUMBER:
mMediaPlayer = getMediaPlayer(context, R.raw.enter_phone_number_login);
break;
case Constance.ENTRY_SYSTEM:
mMediaPlayer = getMediaPlayer(context, R.raw.entry_system);
break;
case Constance.FACE_CHECK_TITLE:
mMediaPlayer = getMediaPlayer(context, R.raw.face_check_titile);
break;
case Constance.ID_CARD_PLACEMENT_INSTRUCTIONS:
mMediaPlayer = getMediaPlayer(context, R.raw.id_card_placement_instructions);
break;
case Constance.ID_INFORMATION_SURE:
mMediaPlayer = getMediaPlayer(context, R.raw.id_information_sure);
break;
case Constance.LOGIN_SUCCESS:
mMediaPlayer = getMediaPlayer(context, R.raw.login_success);
break;
case Constance.PUT_BANK_CARD:
mMediaPlayer = getMediaPlayer(context, R.raw.put_bank_card);
break;
}
}
public static MediaPlayer getMediaPlayer(Context context, int resid) {
mMediaPlayer = MediaPlayer.create(context, resid);
mMediaPlayer.setOnCompletionListener(mListener);
mMediaPlayer.setOnErrorListener(mErroListener);
return mMediaPlayer;
}
}