对于MediaPlayer无法同时播放多个声音的问题,Android提供了声音池工具SoundPool,使用声音池即可对多个声音的播放进度调度。

1.SoundPool优点

  • 资源占用量小,不像MediaPlayer那么耗资源。
  • 相对MediaPlayer来说,延迟时间非常小。
  • 可以同时播放多个音频,从而实现游戏过程中多个声音叠加的情景。

2.SoundPool使用限制

  • SoundPool最大只能申请1MB的内存,这意味着它只能播放一些很短的声音片段,不能用于播放歌曲或者游戏背景音乐。
  • 虽然SoundPool提供了pause和Stop方法,但是轻易不要使用这两个方法,因为他们可能会让App异常或崩溃。
  • SoundPool建议播放ogg格式的音频,据说它对Wav格式的支持不是太好。
  • 待播放的音频要提前加载进声音池,不要等到要播放的时候才加载,否则可能播放没声音。因为SoundPool不会等音频加载完了才播放,而MediaPlayer会等待加载完毕才播放。

3.SoundPool常用方法

  • 构造函数:可设置最大音频个数、音频类型、音频质量。其中音频类型一般是AudioManager.STREAM_MUSIC,音频质量取值为0到100。
  • load:加载指定的音频文件。返回值为该音频的编号。
  • unload:卸载指定编号的音频。
  • play:播放指定编号的音频。可同时设置左右声道的音量(取值为0.0到1.0)、优先级(0为最低)、是否循环播放(0为播放一次,-1为无限循环)、播放速率(取值为0.5-2.0,其中1.0为正常速率)。
  • setVolume:设置指定编号音频的音量大小。
  • setPriority:设置指定编号音频的优先级。
  • setLoop:设置指定编号的音频是否循环播放。
  • setRate:设置指定编号音频的播放速率。
  • pause:暂停播放指定编号的音频。
  • resume:恢复播放指定编号的音频。
  • autoPause:暂停所有正在播放的音频。
  • autoResume:恢复播放所有被暂停的音频。
  • stop:停止播放指定编号的音频。
  • release:释放所有音频资源。
  • setOnLoadCompleteListener:设置音频加载完毕的监听器。需实现接口OnLoadCompleteListener的onLoadComplete方法,该方法在音频加载结束后触发。

4..SoundPool使用示例

public class MainActivity extends WaterPermissionActivity<MainModel>
        implements MainCallback, View.OnClickListener {

    private HashMap<Integer,Integer> mSoundMap;//声音编号映射
    private SoundPool mSoundPool;//声音池对象

    private Button bt_total;
    private Button bt1;
    private Button bt2;
    private Button bt3;

    @Override
    protected MainModel getModelImp() {
        return new MainModel(this,this);
    }

    @Override
    protected int getContentLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected void initWidget() {
        statusBarColor(R.color.white,false);
        bt_total = findViewById(R.id.bt_total);
        bt1 = findViewById(R.id.bt1);
        bt2 = findViewById(R.id.bt2);
        bt3 = findViewById(R.id.bt3);
        bt_total.setOnClickListener(this);
        bt1.setOnClickListener(this);
        bt2.setOnClickListener(this);
        bt3.setOnClickListener(this);
        initSound();
    }

    /**
     * 初始化声音池
     */
    private void initSound(){
        mSoundMap = new HashMap<>();
        mSoundPool = new SoundPool(3, AudioManager.STREAM_MUSIC,100);
        loadSound(1,R.raw.beep1);
        loadSound(2,R.raw.beep2);
        loadSound(3,R.raw.ring);
    }

    /**
     * 把音频资源添加到声音池
     * @param seq
     * @param resid
     */
    private void loadSound(int seq,int resid){
        int soundID = mSoundPool.load(this,resid,1);
        mSoundMap.put(seq,soundID);
    }

    /**
     * 播放指定音频
     * @param seq
     */
    private void playSound(int seq){
        int soundID = mSoundMap.get(seq);
        mSoundPool.play(soundID,1.0f,1.0f,1,0,1.0f);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.bt_total:
                playSound(1);
                playSound(2);
                playSound(3);
                break;
            case R.id.bt1:
                playSound(1);
                break;
            case R.id.bt2:
                playSound(2);
                break;
            case R.id.bt3:
                playSound(3);
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mSoundPool!=null){
            mSoundPool.release();
        }
    }
}