它是一个“pool”,我们可以加载多个音频资源到内存。加载资源到内存是需要花费少许时间的,因此我们需要监听加载资源完毕的事件,在加载完毕后才能进行播放,以免发生不可预期的错误。
除了以上介绍外,SoundPool 还有诸多其他功能,诸如调节左右声道的音量值、调整播放的语速、设置播放的优先级以及播放的次数等等。
SoundPool 的创建
SoundPool 的创建方式在不同版本中会有所不同,为了更好的兼容性,应该对api版本进行判断,再对应的进行创建. 在 5.0 以前 ,直接使用它的构造方法即可,而在这之后,则需要使用Builder模式来创建。
创建完 SoundPool 后,通过setOnLoadCompleteListener设置监听,用来监听资源加载完毕的事件发生。
/**
* 创建SoundPool ,注意 api 等级
*/
private void createSoundPoolIfNeeded() {
if (mSoundPool == null) {
// 5.0 及 之后
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
AudioAttributes audioAttributes = null;
audioAttributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build();
mSoundPool = new SoundPool.Builder()
.setMaxStreams(16)
.setAudioAttributes(audioAttributes)
.build();
} else { // 5.0 以前
mSoundPool = new SoundPool(16, AudioManager.STREAM_MUSIC, 0); // 创建SoundPool
}
mSoundPool.setOnLoadCompleteListener(this); // 设置加载完成监听
}
}
5.0 之前,直接通过SoundPool的构造方法来创建,有三个参数:
1.maxStreams 同时播放流的最大数量,当播放的流的数目大于此值,则会选择性停止优先级较低的流
2.streamType 流类型,比如 STREAM_MUSIC
3.srcQuality 采样率转换器质量,目前没有什么作用,默认填充0
5.0 之后,使用Builder模式进行构造.Builder可以设置多个参数.
setAudioAttributes用来设置audio 属性,此值要么不设,要么设置不为null的值,否则会导致异常产生
如下代码摘录自 SoundPool.Builder 类,可以发现给 setAudioAttributes 传 null 是会抛出异常的,如果不设置的话,在build方法中则会默认创建一个,usage设置为USAGE_MEDIA
public Builder setAudioAttributes(AudioAttributes attributes)
throws IllegalArgumentException {
if (attributes == null) {
throw new IllegalArgumentException("Invalid null AudioAttributes");
}
mAudioAttributes = attributes;
return this;
}
public SoundPool build() {
if (mAudioAttributes == null) {
mAudioAttributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA).build();
}
return new SoundPool(mMaxStreams, mAudioAttributes);
}
AudioAttributes 也是使用Builder模式来构造的,setUsage用来设置用途(比如是游戏还是媒体), setContentType用来设置内容类型(比如是视频还是音乐)
资源加载与播放
当资源没加载时,首先需要调用 SoundPool 的load 方法进行加载,并返回一个mSoundId,它代表一个已加载的资源的id,可以用来播放音效。
加载音频资源异步执行,此过程是需要时间的,当加载成功后,会调用 onLoadComplete 方法
此处的load方法是从res/raw 下加载的,需要注意的是,通过这种方式加载的资源会忽略后缀名,因此不同类型的资源不能重名. 实际上, 提供了多个load 方法, 以方便不同的需求:
// Load the sound from the specified path. 根据路径加载
public int load(String path, int priority)
// Load the sound from the specified APK resource 使用应用的资源
public int load(Context context, int resId, int priority)
// Load the sound from an asset file descriptor 使用 assert 文件描述符
public int load(AssetFileDescriptor afd, int priority) {
// Load the sound from a FileDescriptor. 使用文件描述符
public int load(FileDescriptor fd, long offset, long length, int priority)
通过 unload 方法来卸载之前加载的资源 ,参数为已加载过的资源 id
public native final boolean unload(int soundID);
mStreamID = mSoundPool.play(mSoundId, mCruLeftVolume, mCurRightVolume, 16, -1, 1.0f);
当活跃的stream数量大于maxStreams,调用该方法可导致另一个播放声音被停止:
1.soundID load方法返回的值,指向某个已加载的音频资源
2.leftVolume\rightVolume 左右声道的值.范围 0.0f ~ 1.0f
3.priority 流的优先级
4.loop 循环播放的次数, -1 表示无限循环
5.rate 播放的速率 , 2 表示2倍速度
返回值streamID , 返回0则播放失败,否则成功。通过这个id可以进一步进行控制. 比如 pause\resume
播放控制
streamID是对流的特定实例的引用,通过 SoundPool 的 pause\resume\stop 方法, 就可以对播放进行控制。
pause方法用来暂停指定mStreamID的流 (暂停播放)
resume方法用来恢复指定mStreamID的流 (恢复播放)
stop方法用来停止指定mStreamID的流 (停止播放)
mSoundPool.pause(mStreamID);
播放音量调节
通过 SoundPool 的 setVolume 方法就可以设置指定 mStreamID 的流的左右声道的音量值.
如下,通过SeekBar 进行动态调节
private OnSeekBarChangeListenerAdapter seekBarListener = new OnSeekBarChangeListenerAdapter() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
super.onProgressChanged(seekBar, progress, fromUser);
if(mSoundPool == null) return;
float volume = progress * 1.0f / seekBar.getMax();
switch (seekBar.getId()) {
case R.id.id_sk_left_vloume: // 设置左 volume
mCruLeftVolume = volume;
mSoundPool.setVolume(mStreamID, mCruLeftVolume, mCurRightVolume);
break;
case R.id.id_sk_right_vloume: // 设置又 volume
mCurRightVolume = volume;
mSoundPool.setVolume(mStreamID, mCruLeftVolume, mCurRightVolume);
break;
}
}
};
资源释放
通过unload 方法来卸载之前load的资源 , 并通过 release 方法释放SoundPool占用的资源
/**
* 释放资源
*/
private void releaseSoundPool() {
if (mSoundPool != null) {
mSoundPool.autoPause();
mSoundPool.unload(mSoundId);
mSoundPool.release();
mSoundPool = null;
}
}
注意事项
并不是所有的音频格式都支持,可能有些格式是不支持的
尽量使用占用内存较小的音频文件,时长也不要过长,因为 SoundPool 也只会播放很短的时间
加载资源的数目也需要注意(256限制),过多可能会导致问题
播放之前一定要确保资源以及加载完毕了,否则可能会出现异常情况
设置流的优先级的问题,当同时播放的活动流的数目超过设置的maxStreams值的时候,会根据优先级来停止优先级较低的流,如果有多个具有相同低优先级的流,它将选择要停止的最旧流,并且该流不再有效;如果要播放的流的优先级最低,则会播放失败,返回的streamID为零ID
可以设置播放的重复次数,当设置为-1 则表示会无限循环下去,此时若要停止,需要显示的调用stop() 方法
可以设置播放速率,设置范围为0.5 ~ 2.0 , 正常为 1.0