播放短音乐有时播放一半问题解决方案

1,250 阅读2分钟

1,背景

在推送到达时,会播放一些简单声音,这个声音比较短,大概十几个字,遇到了一个问题,就是同时收到多个推送,同时播放同一个声音,会出现部分声音播放不完全,只播放一半的问题

2,调研

我们播放音乐的方法

MediaPlayer mediaPlayer = MediaPlayer.create(context,R.raw.test_mp3);
mediaPlayer.setVolume(1F, 1F);
mediaPlayer.start();
mediaPlayer.setOnCompletionListener(mp -> mediaPlayer.release());

通过这种方式播放,一次播放没有问题,但是多次调用,就会出现本地音乐只播放一半的问题, 查询问题出现的原因,发现是因为MediaPlayer播放短音乐的时候,会偶尔出现Mediaplayer被GC回收的情况,这个查了很多的博客文档,没找到解决的方案

同时查询文档,发现播放这种短音乐,铃声等比较适合的是SoundPool,接下来,尝试使用SoundPool播放本地短音乐

public void play(){
    SoundPool soundPool;
    if (Build.VERSION.SDK_INT >= 21) {
        SoundPool.Builder builder = new SoundPool.Builder();
        builder.setMaxStreams(1);
        AudioAttributes.Builder attrBuilder = new AudioAttributes.Builder();
        attrBuilder.setLegacyStreamType(AudioManager.STREAM_MUSIC);
        builder.setAudioAttributes(attrBuilder.build());
        soundPool = builder.build();
    } else {
        soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);
    }

    final int voiceId = soundPool.load(context, R.raw.sound, 1);
    soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
        @Override
        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
            if (status == 0) {
                soundPool.play(voiceId, 1, 1, 1, 0, 1);
            }
        }
    });
}

直接调用Play方法,发现还是会出现多次播放播放一半的问题,想一下,MediaPlayer是因为多次播放,都在创建MediaPlayer,导致被GC回收,那么SoundPool应该也是这个问题,修改成单例方式,果然可以

3,最终方案

/**
 * 播放音乐控制类
 * 支持播放较短的音乐
 */
public class VoicePlayManager {

    private static volatile VoicePlayManager mInstance = null;
    private Context mContext;

    private VoicePlayManager(Context context) {
        this.mContext = context;
    }

    public static VoicePlayManager getInstance(Context context) {
        if (mInstance == null) {
            synchronized (PushManager.class) {
                if (mInstance == null) {
                    mInstance = new VoicePlayManager(context);
                }
            }
        }
        return mInstance;
    }


    private SoundPool soundPool = null;

    public void createSoundPool() {
        if (soundPool == null) {
            //实例化SoundPool

            //sdk版本21是SoundPool 的一个分水岭
            if (Build.VERSION.SDK_INT >= 21) {
                SoundPool.Builder builder = new SoundPool.Builder();
                builder.setMaxStreams(1);
                
                AudioAttributes.Builder attrBuilder = new AudioAttributes.Builder(); 
                attrBuilder.setLegacyStreamType(AudioManager.STREAM_MUSIC);
                //加载一个AudioAttributes
                builder.setAudioAttributes(attrBuilder.build());
                soundPool = builder.build();
            } else {
                soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);
            }

        }
    }

    public void playSoundPool(int resId) {

        createSoundPool();
        
        final int voiceId = soundPool.load(mContext, resId, 1);
        soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
            @Override
            public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                if (status == 0) {
             
                    soundPool.play(voiceId, 1, 1, 1, 0, 1);
                }
            }
        });
    }
}

最终调用

VoicePlayManager.getInstance(context).playSoundPool(R.raw.test_mp3);

多次调用,问题没有在出现,解决了问题