Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android應用開發入門(六十)SoundPool的介紹及使用

Android應用開發入門(六十)SoundPool的介紹及使用

編輯:Android開發實例

前言

  在Android中播放音頻文件經常會用到MediaPlayer,但是MediaPlayer存在一些不足的地方,如:資源占用量較高、加載延遲時間較長、不支持多個音頻同時播放等。這些缺點決定了MediaPlayer在某些需要密集使用不同音頻的情況不會理想,例如游戲開發。在游戲開發中,我們經常需要播放一些游戲的音效,這些音效的都需要是短促、密集、延遲小的,在這種場景下,需要使用到SoundPool來替代MediaPlayer播放這些音效,本篇就主要講解SoundPool的使用以及需要注意的地方,最後將以一個示例演示SoundPool的使用。

  本篇的主要內容:

  1. SoundPool
  2. SoundPool的簡單示例
  3. SoundPool的注意事項 

  

SoundPool

  SoundPool(聲音池),所處於"android.media.SoundPool"包下,主要用於播放一些較短的聲音片段,支持從程序的資源或文件系統加載。與MediaPlayer相比,SoundPool的優勢在於CPU的資源占用量低、反應延遲小,並且可以加載多個音頻到SoundPool中,通過資源ID來管理。另外SoundPool還支持執行設置聲音的品質、音量、播放比率等參數。

  SoundPool提供一個構造函數,以下是它的完整簽名:

    SoundPool(int maxStreams,int streamType,int srcQuality)

  通過上面的構造函數即可完成SoundPool的初始化,第一個參數為音頻池最多支持裝載多少個音頻,就是音頻池的大小;第二個參數指定聲音的類型,在AudioManager類中以常量的形式定義,一般指定為AudioManager.STREAM_MUSIC即可;第三個參數為音頻的質量,默認為0,這個參數為預留參數,現在沒有實際意義,為擴展預留字段,一般傳0即可。

 

  對於一個音頻池,涉及到音頻的加載、播放、暫停、繼續、釋放資源等操作,SoundPool也為我們提供了相應的方法,其底層也是用C++編寫的native方法。以下介紹一些常用的SoundPool方法:

  • int load(Context context,int resId,int priority):從一個文件夾raw下裝載一段音頻資源,返回值為音頻資源在SoundPool的ID。
  • int load(String path,int priority):從一個資源文件的路徑裝載一段音頻資源,返回值為音頻資源在SoundPool的ID。
  • final int play(int soundID,float leftVolume,float rightVolume,int priority,int loop,float rate):根據資源ID,播放一段音頻資源。
  • final void pause(int streamID):根據裝載資源ID,暫停音頻資源的播放。
  • final void resume(int streamID):根據裝載資源ID,繼續播放暫停的音頻資源。
  • final void stop(int streamID):根據裝載資源ID,停止音頻資源的播放。
  • final boolean unload(int soundID) :從音頻池中卸載音頻資源ID為soundID的資源。
  • final void release():釋放音頻池資源。

  上面方法無疑Load()和play()是最重要的,Load()具有多種重載方法,從參數名就可以看出是什麼意思。這裡講解一下play()方法,soundID參數為資源ID;leftVolume和rightVolume個參數為左右聲道的音量,從大到小取0.0f~1.0f之間的值;priority為音頻質量,暫時沒有實際意義,傳0即可;loop為循環次數,0為播放一次,-1為無線循環,其他正數+1為播放次數,如傳遞3,循環播放4次;rate為播放速率,從大到小取0.0f~2.0f,1.0f為正常速率播放。

  在使用load()裝載音頻的時候需要注意,load()方法是一個異步的方法,也就是說,在播放音頻的時候,很可能此段音頻還沒有裝載到音頻池中,這裡可以借助SoundPool的一個裝載完成的監聽事件SoundPool.setOnLoadCompleteListener來保證裝載完成在播放聲音。SoundPool.setOnLoadCompleteListener()需要實現一個SoundPool.OnLoadCompleteListener接口,其中需要實現onLoadComplete()方法,一下是onLoadComplete()方法的完整簽名:

    onLoadComplete(SoundPool soundPool, int sampleId, int status)

  • soundPool:當前觸發事件的聲音池。
  • sampleId:當前裝載完成的音頻資源在音頻池中的ID。
  • status:狀態碼,展示沒有意義,為預留參數,會傳遞0。

 

使用SoundPool示例

  上面已經介紹了SoundPool的使用所涉及到的內容,下面通過一個簡單的示例來演示一下SoundPool的使用,播放的音頻資源都是我從其他app中拷貝出來的,沒有實際意義。示例中的注釋寫的比較全,這裡不再累述了。

  1. package cn.bgxt.soundpooldemo;  
  2.  
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.  
  6. import android.media.AudioManager;  
  7. import android.media.SoundPool;  
  8. import android.media.SoundPool.OnLoadCompleteListener;  
  9. import android.os.Bundle;  
  10. import android.app.Activity;  
  11. import android.util.Log;  
  12. import android.view.View;  
  13. import android.view.View.OnClickListener;  
  14. import android.widget.Button;  
  15. import android.widget.Toast;  
  16.  
  17. public class MainActivity extends Activity {  
  18.     private Button btn_newqqmsg, btn_newweibontf, btn_newweibotoast;  
  19.     private SoundPool pool;  
  20.     private Map<String, Integer> poolMap;  
  21.  
  22.     @Override 
  23.     protected void onCreate(Bundle savedInstanceState) {  
  24.         super.onCreate(savedInstanceState);  
  25.         setContentView(R.layout.activity_main);  
  26.         btn_newqqmsg = (Button) findViewById(R.id.btn_newqqmsg);  
  27.         btn_newweibontf = (Button) findViewById(R.id.btn_newweibontf);  
  28.         btn_newweibotoast = (Button) findViewById(R.id.btn_newweibotoast);  
  29.  
  30.         poolMap = new HashMap<String, Integer>();  
  31.         // 實例化SoundPool,大小為3  
  32.         pool = new SoundPool(3, AudioManager.STREAM_MUSIC, 0);  
  33.         // 裝載音頻進音頻池,並且把ID記錄在Map中  
  34.         poolMap.put("newqqmsg", pool.load(this, R.raw.qqmsg, 1));  
  35.         poolMap.put("newweibontf", pool.load(this, R.raw.notificationsound, 1));  
  36.         poolMap.put("newweibotoast", pool.load(this, R.raw.newblogtoast, 1));  
  37.  
  38.         pool.setOnLoadCompleteListener(new OnLoadCompleteListener() {  
  39.  
  40.             @Override 
  41.             public void onLoadComplete(SoundPool soundPool, int sampleId,  
  42.                     int status) {  
  43.                 // 每次裝載完成均會回調  
  44.                 Log.i("main", "音頻池資源id為:" + sampleId + "的資源裝載完成");  
  45.                 // 當前裝載完成ID為map的最大值,即為最後一次裝載完成  
  46.                 if (sampleId == poolMap.size()) {  
  47.                     Toast.makeText(MainActivity.this, "加載聲音池完成!",  
  48.                             Toast.LENGTH_SHORT).show();  
  49.                     btn_newqqmsg.setOnClickListener(click);  
  50.                     btn_newweibontf.setOnClickListener(click);  
  51.                     btn_newweibotoast.setOnClickListener(click);  
  52.                     // 進入應用播放四次聲音  
  53.                     pool.play(poolMap.get("newweibotoast"), 1.0f, 1.0f, 0, 3,  
  54.                             1.0f);  
  55.                 }  
  56.             }  
  57.         });  
  58.     }  
  59.  
  60.     private View.OnClickListener click = new OnClickListener() {  
  61.  
  62.         @Override 
  63.         public void onClick(View v) {  
  64.  
  65.             switch (v.getId()) {  
  66.             case R.id.btn_newqqmsg:  
  67.                 if (pool != null) {  
  68.                     pool.play(poolMap.get("newqqmsg"), 1.0f, 1.0f, 0, 0, 1.0f);  
  69.                 }  
  70.                 break;  
  71.             case R.id.btn_newweibontf:  
  72.                 if (pool != null) {  
  73.                     pool.play(poolMap.get("newweibontf"), 1.0f, 1.0f, 0, 0,  
  74.                             1.0f);  
  75.                 }  
  76.                 break;  
  77.             case R.id.btn_newweibotoast:  
  78.                 if (pool != null) {  
  79.                     pool.play(poolMap.get("newweibotoast"), 1.0f, 1.0f, 0, 0,  
  80.                             1.0f);  
  81.                 }  
  82.                 break;  
  83.             default:  
  84.                 break;  
  85.             }  
  86.         }  
  87.     };  
  88.  
  89.     @Override 
  90.     protected void onDestroy() {  
  91.         // 銷毀的時候釋放SoundPool資源  
  92.         if (pool != null) {  
  93.             pool.release();  
  94.             pool = null;  
  95.         }  
  96.         super.onDestroy();  
  97.     }  

 效果展示:

 

SoundPool使用的注意事項

  因為SoundPool的一些設計上的BUG,從固件版本1.0開始就有些沒有修復的,以後應該會慢慢修復。這裡簡單提一下:

  1. 雖然SoundPool可以裝載多個音頻資源,但是最大只能申請1MB的內存空間,這就意味著只能用使用它播放一些很短的聲音片段,而不是用它來播放歌曲或者做游戲背景音樂。
  2. SoundPool提供的pause()、resume()、stop()最好不要輕易使用,因為它有時候會使程序莫名其妙的終止,如果使用,最好做大量的測試。而且有時候也不會立即終止播放聲音,而是會等緩沖區的音頻數據播放完才會停止。
  3. 雖然SoundPool比MediaPlayer的效率好,但也不是絕對不存在延遲的問題,尤其在那些性能不太好的手機中,SoundPool的延遲問題會更嚴重,但是現在一般的手機配置,那一點的延遲還是可以接受的。

 

  源碼下載

 

總結

  本篇介紹了SoundPool的使用,雖然SoundPool還有一些不足的地方,當時對於應用中一些簡短的特效音,如按鍵音、短消息音,或者一些游戲中密集的聲音,如射擊的槍聲,爆破的聲音等。都是可以使用SoundPool的,效率會比使用MediaPlayer要高的多。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved