忙了两天终于得空写点东西,感慨良多,今天主要总结一下,这个SoundPool的使用,以及注意事项。
首先,SoundPool的定位,她是一个音效播放的执行者,这跟MediaPlayer的最终效果是一样的,她们都是用来播放音乐的。
今天,我们主讲一下,SoundPool这个类。附带的说一说她与MediaPlayer的区别。
下面我们说一下SoundPool播放音频的实现步骤:
1. new出一个实例 ;
1 | new SoundPool( int maxStream, int streamType, int srcQuality); |
maxStream —— 同时播放的流的最大数量
streamType —— 流的类型,一般为STREAM_MUSIC(具体在AudioManager类中列出)
srcQuality —— 采样率转化质量,当前无效果,使用0作为默认值
比如说,
new SoundPool(4, AudioManager.STREAM_MUSIC, 100);
创建了一个最多支持4个流同时播放的,类型标记为音乐的SoundPool。
2.加载
一般把多个声音放到HashMap中去,比如
soundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 100);
soundPoolMap = new HashMap<Integer, Integer>();
soundPoolMap.put(1, soundPool.load(this, R.raw.ring, 1));
当然,我们也可以加载单个的Music,那我们怎么实现播放指定的Music呢?
有关载入音效的方法,有以下几种方法:
1 | int load(Context context, int resId, int priority) //从APK资源载入(就是说,在你码代码的时候工程中的文件。比如,我在res/raw这个文件夹中放了一个ring.mp3,那,resIdential就是 R.raw.ring) |
2 | int load(FileDescriptor fd, long offset, long length, int priority) //从FileDescriptor对象载入 |
3 | int load(AssetFileDescriptor afd, int priority) //从Asset对象载入 |
4 | int load(String path, int priority) //从完整文件路径名载入 |
6 | 所有的最后一个参数 priority 是优先级。这里用于播放多个文件时,系统会优先处理。 |
3,播放
play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate);
其中soundID,就是刚刚load方法得到的那个int型参数,leftVolume和rightVolume表示左右音量,priority表示优先级,loop表示循环次数,rate表示速率,如
//速率最低0.5最高为2,1代表正常速度
1 | sp.play(soundId, 1 , 1 , 0 , 0 , 1 ); |
4,停止
停止可以使用 pause(int streamID) 方法,这里的streamID和soundID均在构造SoundPool类的第一个参数中指明了总数量,而id从0开始。
OK,这就是一个SoundPool的流程,可是,有人要问了,为什么我按这个流程写下来,却没有播放呢?
不饶弯子,因为,在play之前Soundpool没有初始化完毕,那我们如何知道,Soundpool的load已经完毕了呢?Android提供了检测是否初始化完毕的方法,SoundPool.OnLoadCompleteListener;但是这个方法是从SDK2.2才开始有的。所以找错之前,先看看自己的平台。。。
下面讲下两个播放形式的利弊:
一,使用MediaPlayer来播放音频文件存在一些不足:
例如:资源占用量较高、延迟时间较长、不支持多个音频同时播放等。
这些缺点决定了MediaPlayer在某些场合的使用情况不会很理想,所有,一般的游戏开发都是用的Soundpool。
在没有了解Soundpool之前,我也是使用的普通的MediaPlayer进行文件播放,但这个方法不适合用于游戏开发,因为游戏里面经常要同时播放几个音乐文件,用过MediaPlayer的朋友都该知道,它是不支持实时播放多个声音的,而且还会出现或多或少的延迟,尤其是在快速连续播放声音(比如连续猛点按钮)时,会非常明显,长的时候会出现3~5秒的延迟,【使用MediaPlayer.seekTo() 这个方法来解决此问题】;
相对于使用SoundPool存在的一些问题:
1. SoundPool是为播放小文件而存在的。一般限定Soundpool播放文件的大小为1M。
2. SoundPool提供了pause和stop方法,但这些方法建议最好不要轻易使用,因为有些时候它们可能会使你的程序莫名其妙的终止。还有些朋友反映它们不会立即中止播放声音,而是把缓冲区里的数据播放完才会停下来,也许会多播放一秒钟。
3. 音频格式建议使用OGG格式。使用WAV格式的音频文件存放游戏音效,经过反复测试,在音效播放间隔较短的情况下会出现异常关闭的情况(有说法是SoundPool目前只对16bit的WAV文件有较好的支持)。后来将文件转成OGG格式,问题得到了解决。
4.在使用SoundPool播放音频的时候,如果在初始化中就调用播放函数进行播放音乐那么根本没有声音,不是因为没有执行,而是SoundPool需要一准备时间!这就是刚刚我们说的用OnLoadCompleteListener来解决的问题。如果你非得是1.6甚至更低的话,那建议在播放的时候,将play放到一个点击事件中去,当然在这个中也要注意一下两点。
a、 别忘记绑定操作! mp.setOnCompletionListener(this);
b、如果你设置了循环播放 mp.setLooping(true); 的话,那么永远都不会监听到播放完成的状态!!
下面分享一下源码,
01 | import android.app.Activity; |
02 | import android.media.AudioManager; |
03 | import android.media.SoundPool; |
04 | import android.os.Bundle; |
05 | import android.os.Handler; |
06 | import android.os.Message; |
07 | import android.view.View; |
08 | import android.view.View.OnClickListener; |
09 | import android.widget.Button; |
10 | import android.media.SoundPool.OnLoadCompleteListener;</p> |
11 | public class DemoActivity extends Activity implements SoundPool.OnLoadCompleteListener{ |
13 | private Button button; |
14 | private SoundPool sndPool; |
16 | private static final int SOUND_LOAD_OK = 1 ; |
17 | private final Handler mHandler = new MyHandler() ; |
19 | public void onCreate(Bundle savedInstanceState) { |
20 | super .onCreate(savedInstanceState); |
21 | setContentView(R.layout.main); |
22 | button = (Button)findViewById(R.id.button1); |
23 | sndPool = new SoundPool( 10 , AudioManager.STREAM_SYSTEM, 0 ); |
24 | sndPool.setOnLoadCompleteListener( this ); |
25 | hitOkSfx = sndPool.load( this , R.raw.ring, 1 ); |
26 | button.setOnClickListener( new OnClickListener() { |
28 | public void onClick(View v) { |
29 | // TODO Auto-generated method stub |
30 | sndPool.play(hitOkSfx, 10 , 10 , 0 , 0 , ( float ) 1 ); //播放铃声 |
35 | protected void onDestroy() { |
36 | // TODO Auto-generated method stub |
38 | sndPool.stop(hitOkSfx); |
42 | private class MyHandler extends Handler { |
43 | public void handleMessage(Message msg){ |
46 | sndPool.play(hitOkSfx, 10 , 10 , 0 , 0 , ( float ) 1 ); //播放铃声 |
52 | public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { |
53 | // TODO Auto-generated method stub |
54 | Message msg = mHandler.obtainMessage(SOUND_LOAD_OK); ; |
56 | mHandler.sendMessage(msg); |
这个就到这里了吧。。。
转自:http://www.andcoder.com/archives-2011-08-173.html