解決Android SoundPool播放多個音效沒有播放完成回調通知

一、在我們需要播放一些短促的音樂或者音效的時候(播放mp3文件),通常會使用SoundPoolApi來播放因爲可以對音頻文件進行預加載至內存中從而能夠迅速播放出來

二、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();
            }
        }
    }
}

每次開始播放音頻後將線程休眠音頻的時長,然後在繼續播放下一個音頻就可以了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章