SoundPoolhtml
1、基本概念java
在Android應用程序的開發過程當中,常常須要播放多媒體文件,也許最早想到的會是MediaPlayer類了,該類提供了播放、暫停、中止及重複播放等功能性方法(該類位於android.media包下,詳見API文檔)。也可參考博文http://www.cnblogs.com/tgyf/p/4700177.html。android
但使用MediaPlayer類的問題是佔用資源較多,對於遊戲這樣複雜、簡短配音多的應用可能不是很適合,這時候就須要用到SoundPool類了,其定義在SDK的android.media.SoundPool文件中,顧名思義是聲音池的意思。主要用於播放一些較短的聲音片斷,能夠從程序的資源或文件系統加載,相對於MediaPlayer類能夠作到使用較少的CPU資源和較短的反應延遲。app
SoundPool類和其餘聲音播放類相比,優勢是能夠自行設置聲音的品質、音量、播放速率等參數,並且能夠同時管理多個音頻流,每一個流都有獨自的ID,對每一個音頻流的管理都是經過該ID進行的。異步
2、使用流程ide
一、建立實例函數
建立一個SoundPool類實例,(構造函數)方法爲public SoundPool(int maxStream, int streamType, int srcQuality)。三個參數的含義以下:oop
maxStream——同時播放的流的最大個數;測試
streamType——流的類型(通常爲STREAM_MUSIC,具體定義見在AudioManager類);this
srcQuality——採樣率轉化質量,使用0做爲默認值(目前設置並沒有效果);
舉例:
1 SoundPool soundPool = new SoundPool(5,AudioManager.STREAM_MUSIC, 0);
建立了一個最多支持5個流同時播放的,類型標記爲音樂的SoundPool。
二、加載音頻
能夠經過如下四種途徑來加載一個音頻文件資源:
int load(AssetFileDescriptor afd, int priority),經過一個AssetFileDescriptor對象;
int load(Context context, int resId, int priority),經過一個資源ID;
int load(String path, int priority),經過指定的路徑加載;
int load(FileDescriptor fd, long offset, long length, int priority),經過FileDescriptor加載;
注意,API文檔中指出,方法最後一個設置音頻流優先級的參數priority目前沒有效果,建議設置爲1。
一個SoundPool類實例能同時管理多個音頻,因此能夠經過屢次調用load(…)方法來加載,若是加載成功則返回一個非0的soundID ,用於播放時指定具體的音頻流。以下面的代碼所示,音頻資源是以上述第二種方法進行加載:
1 int soundID1 = soundPool.load(this, R.raw.sound1, 1); 2 if(soundID1 == 0){ 3 // 記載失敗 4 }else{ 5 // 加載成功 6 } 7 int soundID2 = soundPool.load(this, R.raw.sound2, 1); 8 ...
這裏加載了兩個流,並分別記錄了返回的soundID,理論上是每load一次,返回的ID值就會加1。
在實際應用中,若音頻文件過多,那借助HashMap類會方便不少。如音頻資源加載先後soundID的賦值與提取過程以下:
1 //加載兩個音頻資源 2 HashMap soundMap=new HashMap<Integer, Integer>(); 3 soundMap.put(1, soundPool.load(MainActivity.this, R.raw.sound1, 1)); 4 soundMap.put(2, soundPool.load(MainActivity.this, R.raw.sound2, 1)); 5 //提取soundID,播放時直接寫入play()方法中做爲參數便可 6 soundMap.get(1);
須要注意的是,流的加載過程是一個將音頻解壓爲原始16位PCM數據,由一個後臺線程經過異步處理的過程。所以,初始化後並不能當即播放,須要等待一點時間。
三、播放控制
SoundPool類用於控制播放的函數主要有如下幾個:
final int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate),播放指定音頻的音效,並返回一個streamID(同soundID,也是隨着音頻播放個數的增長而增長)。函數各個參數含義以下:
leftVolume——最小音量;
rightVolume——最大音量;
priority——流的優先級,值越大優先級高,影響當同時播放數量超出了最大支持數時SoundPool對該流的處理;
loop——循環播放的次數,0爲只播放一次,-1爲無限循環,其餘值爲播放loop+1次(例如,3爲一共播放4次);
rate——播放的速率,範圍0.5-2.0(0.5爲一半速率,1.0爲正常速率,2.0爲兩倍速率);
final void pause(int streamID) ,暫停指定播放流的音效(streamID 應經過play()返回,下同);
final void resume(int streamID) ,繼續播放指定播放流的音效;
final void stop(int streamID) 終止指定播放流的音效;
這裏有四點須要注意一下:
A、play()函數傳遞的是一個load()方法返回的soundID——指向一個被加載的音頻資源,若是播放成功則返回一個非0的streamID——指向一個成功播放的流;同一個soundID能夠經過屢次調用play()而得到多個不一樣的streamID (只要不超出同時播放的最大數量);
B、pause()、resume()及stop()是針對播放流操做的,傳遞的是play()返回的streamID;
C、play()中的priority參數,只在同時播放的流的數量超過了預先設定的最大數量時纔會起做用,管理器將自動終止優先級低的播放流。若是存在多個一樣優先級的流,再進一步根據其建立事件來處理,新建立的流的年齡是最小的,將最早被終止;
D、不管如何,程序退出時,手動終止播放並釋放資源是必要的;
4. 屬性設置
經過獨立的方法來設置傳遞給播放函數paly()的一些參數,主要是後面四個參數。
final void setLoop(int streamID, int loop),設置指定播放流的循環;
final void setVolume(int streamID, float leftVolume, float rightVolume),設置指定播放流的音量;
final void setPriority(int streamID, int priority),設置指定播放流的優先級,上面已說明priority的做用;
final void setRate(int streamID, float rate),設置指定播放流的速率,0.5-2.0;
五、釋放資源
通常用到如下兩個函數:
final boolean unload(int soundID),卸載一個指定的音頻資源;
final void release(),釋放SoundPool中的全部音頻資源;
3、示例代碼
先貼上整個Java代碼:
1 package com.xxx.soundpool; 2 3 import android.app.Activity; 4 import android.media.AudioManager; 5 import android.media.SoundPool; 6 import android.os.Bundle; 7 import android.view.View; 8 import android.widget.Button; 9 import android.widget.TextView; 10 11 import java.util.HashMap; 12 import java.util.Map; 13 14 public class MainActivity extends Activity { 15 private Button wav1_play = null; 16 private Button wav2_play = null; 17 private Button wav3_play = null; 18 private Button wav4_play = null; 19 private Button wav5_play = null; 20 private TextView name = null; 21 22 private SoundPool soundPool = null; 23 24 private Map<Integer, Integer> soundMap = null; 25 26 @Override 27 protected void onCreate(Bundle savedInstanceState) { 28 super.onCreate(savedInstanceState); 29 setContentView(R.layout.activity_main); 30 31 wav1_play = (Button)findViewById(R.id.wav1_play); 32 wav2_play = (Button)findViewById(R.id.wav2_play); 33 wav3_play = (Button)findViewById(R.id.wav3_play); 34 wav4_play = (Button)findViewById(R.id.wav4_play); 35 wav5_play = (Button)findViewById(R.id.wav5_play); 36 name = (TextView)findViewById(R.id.name); 37 38 //建立一個SoundPool對象,該對象能夠容納5個音頻流 39 soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC,0); 40 41 soundMap = new HashMap<Integer, Integer>(); 42 soundMap.put(1, soundPool.load(MainActivity.this, R.drawable.wav1, 1)); 43 soundMap.put(2, soundPool.load(MainActivity.this, R.drawable.wav2, 1)); 44 soundMap.put(3, soundPool.load(MainActivity.this, R.drawable.wav3, 1)); 45 soundMap.put(4, soundPool.load(MainActivity.this, R.drawable.wav4, 1)); 46 soundMap.put(5, soundPool.load(MainActivity.this, R.drawable.wav5, 1)); 47 48 wav1_play.setOnClickListener(new View.OnClickListener() { 49 @Override 50 public void onClick(View arg0) { 51 // TODO Auto-generated method stub 52 soundPool.play(soundMap.get(1), 1, 1, 0, 0, 1); 53 name.setText("wav1.wav"); 54 } 55 }); 56 wav2_play.setOnClickListener(new View.OnClickListener() { 57 @Override 58 public void onClick(View arg0) { 59 // TODO Auto-generated method stub 60 soundPool.play(soundMap.get(2), 1, 1, 0, 0, 1); 61 name.setText("wav2.wav"); 62 } 63 }); 64 wav3_play.setOnClickListener(new View.OnClickListener() { 65 @Override 66 public void onClick(View arg0) { 67 // TODO Auto-generated method stub 68 soundPool.play(soundMap.get(3), 1, 1, 0, 0, 1); 69 name.setText("wav3.wav"); 70 } 71 }); 72 wav4_play.setOnClickListener(new View.OnClickListener() { 73 @Override 74 public void onClick(View arg0) { 75 // TODO Auto-generated method stub 76 soundPool.play(soundMap.get(4), 1, 1, 0, 0, 1); 77 name.setText("wav4.wav"); 78 } 79 }); 80 wav5_play.setOnClickListener(new View.OnClickListener() { 81 @Override 82 public void onClick(View arg0) { 83 // TODO Auto-generated method stub 84 soundPool.play(soundMap.get(5), 1, 1, 0, 0, 1); 85 name.setText("wav5.wav"); 86 } 87 }); 88 } 89 }
能夠看到,事先準備好的五個音頻資源(名稱分別爲wav1.wav,wav2.wav,wav3.wav,wav4.wav,wav5.wav),直接放到了drawable目錄下。點擊按鈕會播放相對應的音頻資源,在頂部的TextView組件會顯示當前播放的文件名稱,並且和預想的同樣,連續點擊幾個按鈕,可以達到幾個音頻同時播放的效果。
不過不知道爲何,這樣的實現方式運行後播放的音效只有幾秒鐘,查了一下,網上不少人遇到過相似問題,5、六秒的樣子。至於播放中止(stop()),復播(resume())等操做就比較簡單了,這裏未加入測試代碼中,感興趣的小夥伴能夠本身實現下。
簡單界面以下:
4、總結
經過SoundPool類來加載、播放及釋放資源的過程,須要掌握如下六點:
一、管理多個音頻資源,經過load()函數,成功則返回非0的soundID;
二、同時播放多個音頻,經過play()函數,成功則返回非0的streamID;
三、pause()、resume()及stop()等操做是針對streamID(播放流)的;
四、當設置爲無限循環時,須要手動調用stop()來終止播放;
五、播放流的優先級(play()中的priority參數),只在同時播放數超過設定的最大數時纔會起做用;
六、程序中不用考慮(play()觸發的)播放流的生命週期,無效的soundID or streamID不會致使程序錯誤。