最近在测试程序的时候发现,SoundPool的load()方法在主线程里创建多了就会很卡顿。
我在Frament里的onCreateView()方法里面加载了14个声音明显的感觉到了卡顿。
所以我这里做的优化就是点击按钮之后才再去加载和播放声音,这样可以避免主线程性能的消耗。
思路已经知道了,立马我就想到这样去写:
soundPool.play(soundPool.load(context, R.raw.num0, 1), 1, 1, 1, 0, 1);
写了之后测试时立马就出现问题了,什么情况~没有声音了!
原来load()方法是异步的。也就是说我在play播放的时候load方法还没有加载完成呢。
所以OnLoadCompleteListener这个接口就派上用场了。以下是我写一个数字键盘简单计算器小程序可以播放声音(实现点击按钮之后再去加载和播放声音的效果)。别的不多说了直接贴上源码了:
public class MySoundPool {
/**
* 创建一个声音池
* @param MaxStreams 最大流数量
* @return
*/
@SuppressWarnings("deprecation")
public static SoundPool Create(int MaxStreams) {
SoundPool soundPool;
if (Build.VERSION.SDK_INT >= 21) {
AudioAttributes.Builder attrBuilder = new AudioAttributes.Builder();
attrBuilder.setLegacyStreamType(AudioManager.STREAM_MUSIC);
Builder SoundPoolbuild = new SoundPool.Builder();
SoundPoolbuild.setMaxStreams(MaxStreams);
SoundPoolbuild.setAudioAttributes(attrBuilder.build());
soundPool = SoundPoolbuild.build();
} else {
soundPool = new SoundPool(MaxStreams, AudioManager.STREAM_MUSIC, 5);
}
return soundPool;
}
}
主要实现类:
private int nowSoundNum;
private SoundPool soundPool;
private OnLoadCompleteListener SoundLoadListener;
private HashMap soundID = new HashMap();
private static final int mNum0 = 0;
private static final int mNum1 = 1;
private static final int mNum2 = 2;
private static final int mNum3 = 3;
private static final int mNum4 = 4;
private static final int mNum5 = 5;
private static final int mNum6 = 6;
private static final int mNum7 = 7;
private static final int mNum8 = 8;
private static final int mNum9 = 9;
private static final int mNum10dian = 10;
private static final int mNum11jia = 11;
private static final int mNum12clear = 12;
private static final int mNum13bk = 13;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
soundPool = MySoundPool.Create(14);// 创建声音池
...
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_0:
PlaykeyboardSound(mNum0);
break;
case R.id.btn_1:
PlaykeyboardSound(mNum1);
break;
case R.id.btn_2:
PlaykeyboardSound(mNum2);
break;
...
}
}
private void PlaykeyboardSound(int key) {
nowSoundNum = key;
if (soundID.get(key) == null) {
if (SoundLoadListener == null) {
SoundLoadListener = new OnLoadCompleteListener() {
@Override
public void onLoadComplete(SoundPool soundPool,int sampleId, int status) {
SaveSoundIDandPlay(sampleId);
}
};
soundPool.setOnLoadCompleteListener(SoundLoadListener);
}
switch (key) {
case mNum0:
soundPool.load(activity, R.raw.num0, 1);
break;
case mNum1:
soundPool.load(activity, R.raw.num1, 1);
break;
case mNum2:
soundPool.load(activity, R.raw.num2, 1);
break;
case mNum3:
soundPool.load(activity, R.raw.num3, 1);
break;
case mNum4:
soundPool.load(activity, R.raw.num4, 1);
break;
case mNum5:
soundPool.load(activity, R.raw.num5, 1);
break;
case mNum6:
soundPool.load(activity, R.raw.num6, 1);
break;
case mNum7:
soundPool.load(activity, R.raw.num7, 1);
break;
case mNum8:
soundPool.load(activity, R.raw.num8, 1);
break;
case mNum9:
soundPool.load(activity, R.raw.num9, 1);
break;
case mNum10dian:
soundPool.load(activity, R.raw.num10point, 1);
break;
case mNum11jia:
soundPool.load(activity, R.raw.num11jia, 1);
break;
case mNum12clear:
soundPool.load(activity, R.raw.num12clear, 1);
break;
case mNum13bk:
soundPool.load(activity, R.raw.num13delete, 1);
break;
}
} else {
soundPool.play(soundID.get(key), 1, 1, 0, 0, 1);
}
}
private synchronized void SaveSoundIDandPlay(int sampleId) {
soundPool.play(sampleId, 1, 1, 1, 0, 1);
soundID.put(nowSoundNum, sampleId);
}
saveSoundIDAndPlay方法为什么要加同步锁。其实还是因为load的原因,因为load是异步的。当saveSoundIDAndPlay方法不加同步锁的时候,你快速点击多个按钮后这几个按钮的声音同时开始加载了,就有可能同时播放了,所以还是要让它按顺序播放。