解决Android SoundPool播放多个音效没有播放完成回调通知
一、在我们需要播放一些短促的音乐或者音效的时候(播放mp3文件),通常会使用SoundPool
Api来播放因为可以对音频文件进行预加载至内存中从而能够迅速播放出来
二、SoundPool
的简单使用
SoundPool soundPool = new SoundPool.Builder().build();
int soundId = soundPool.load(App.getApplication(), R.raw.mp3_0, 1);
soundPool.play(soundId, 1, 1, 0, 0, 1);
- 通过建造者模式创建
SoundPool
- 通过
SoundPool
加载一个音频文件至内存中并返回这个音频在SoundPool
内的ID - 通过
SoundPool.play()
传入音频的ID进行播放;
如上就是使用SoundPool
的整个流程
三、当你需要按顺序进行多个音效播放的时候你会发现SoundPool
并没有提供播放完成的回调通知那我们怎么才能实现呢?
- 只提供了一个加载音效至内存的完成监听器,所以我们得通过一定的骚操作来实现
播放完成的通知也就是从开始播放到播完这个音效的时长,也就是这个音效的时长;所以我们只需在初始化的时候获取到音效的时长即可
四、音效初始化的时候通过MediaPlayer
获取到音效的时长,然后将soundId
和时长存入Map中
protected void init() {
//保存音效ID和对应的音效时长
Map<Integer, Integer> soundIdMap = new HashMap<>();
SoundPool soundPool = new SoundPool.Builder().build();
Integer[] mp30 = loadRaw(soundPool, App.getApplication(), R.raw.mp3_0);
Integer[] mp31 = loadRaw(soundPool, App.getApplication(), R.raw.mp3_1);
Integer[] mp32 = loadRaw(soundPool, App.getApplication(), R.raw.mp3_2);
soundIdMap.put(mp30[0], mp30[1]);
soundIdMap.put(mp31[0], mp32[1]);
soundIdMap.put(mp32[0], mp32[1]);
}
/**
* 加载音频文件
*/
private Integer[] loadRaw(SoundPool soundPool, Context context, int raw) {
int soundId = soundPool.load(context, raw, 1);
int duration = getMp3Duration(context, raw);
return new Integer[]{soundId, duration};
}
/**
* 获取音频文件的时长
*/
private int getMp3Duration(Context context, int rawId) {
try {
Uri uri = Uri.parse("android.resource://" + context.getPackageName() + "/" + rawId);
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(context, uri);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.prepare();
return mediaPlayer.getDuration();
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
五、相信大家都听说过睡眠排序算法
吧,没看错这里就是通过睡眠法将音频按顺序播放,如下:
- 启动一个播放线程
/**
* 音频播放线程
*/
private class PlayThread extends Thread {
@Override
public void run() {
Set<Integer> soundIdSet = soundIdMap.keySet();
for (Integer soundId : soundIdSet) {
soundPool.play(soundId, 1, 1, 0, 0, 1);
try {
//获取当前音频的时长
Thread.sleep(soundIdMap.get(soundId));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
每次开始播放音频后将线程休眠音频的时长,然后在继续播放下一个音频就可以了
本文由 创作,采用 知识共享署名4.0 国际许可协议进行许可。本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。最后编辑时间为: 2021/01/07 02:30