背景
在一个小游戏项目中涉及到音频播放的功能:
其中有反馈:
代码研究
原来是旧有逻辑使用了SoundPool
的代码逻辑,该逻辑会导致上述情况。
解决方式是使用mediaPlayer
实现:
改装时候的代码:
public class AudioPlayer {
private MediaPlayer mediaPlayer;
private HashMap<String, String> namePathMap = new HashMap<>();
private String savePath = CommonUtils.getDataBaseFile(CommonUtils.getApplication()) + "/audio/";
private Handler handler = new Handler(Looper.getMainLooper());
//实例化AudioManager对象,控制声音
private AudioManager am;
//最大音量
private float audioMaxVolume;
//当前音量
private float audioCurrentVolume;
private float volumeRatio;
public AudioPlayer() {
// 设置音效使用场景
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
//实例化AudioManager对象,控制声音
am = (AudioManager)CommonUtils.getApplication().getSystemService(Context.AUDIO_SERVICE);
//最大音量
audioMaxVolume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
//当前音量
audioCurrentVolume = am.getStreamVolume(AudioManager.STREAM_MUSIC);
volumeRatio = audioCurrentVolume / audioMaxVolume;
// 准备是耗时的,故异步处理
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
});
}
String path = null;
public void playSound(String name, boolean isPlay, String url, boolean isLoop, int volume){
if (mediaPlayer == null) {
AudioAttributes attr = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_GAME)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build();
mediaPlayer = new MediaPlayer();
}
if(mediaPlayer.isPlaying() == isPlay && path == namePathMap.get(url)){
return;
}
path = namePathMap.get(url);
mediaPlayer.setLooping(isLoop);
mediaPlayer.setVolume(volumeRatio * volume / 100, volumeRatio * volume / 100);
if (path == null) {
// 下载
CommonUtils.downloadFile(url, savePath, new ICommonCallback<String>() {
@Override
public void onResult(int errorCode, String object) {
if (errorCode == 0 && !TextUtils.isEmpty(object)) {
namePathMap.put(url, object);
path = object;
play(path,isPlay);
}
}
});
} else {
play(path,isPlay);
}
}
private void play(String path,boolean isPlay){
try {
mediaPlayer.setDataSource(path);
if (isPlay) {
mediaPlayer.prepareAsync();
return;
} else {
mediaPlayer.stop();
}
}catch (IOException e){
e.printStackTrace();
}
}
public void changeSoundVolume(String name, int volume) {
if (mediaPlayer == null) {
return;
}
mediaPlayer.setVolume(volumeRatio * volume / 100, volumeRatio * volume / 100);
}
public void release() {
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
}
}
public void pause() {
if (mediaPlayer != null) {
mediaPlayer.pause();
}
}
public void resume() {
if (mediaPlayer != null) {
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
}
}
在使用prepareAsync()
要注意对回调设置:
// 准备是耗时的,故异步处理
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
});
这里的逻辑是准备好就可以播放了。