1. 程式人生 > >Android之 MediaPlayer播放一般音訊與SoundPool播放短促的音效

Android之 MediaPlayer播放一般音訊與SoundPool播放短促的音效

【1】使用MediaPlayer實現一般的音訊播放
  • MediaPlayer播放通常的音訊檔案
[java] view plaincopyprint?
  1. MediaPlayer mediaPlayer = new MediaPlayer();  
  2. if (mediaPlayer.isPlaying()) {  
  3.    mediaPlayer.reset();//重置為初始狀態
  4. }  
  5. mediaPlayer.setDataSource("/mnt/sdcard/god.mp3");  
  6. mediaPlayer.prepare();//緩衝 
  7. mediaPlayer.start();//開始或恢復播放
  8. mediaPlayer.pause();//暫停播放
  9. mediaPlayer.start();//恢復播放
  10. mediaPlayer.stop();//停止播放
  11. mediaPlayer.release();//釋放資源
  12. mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {//播出完畢事件
  13.         @Overridepublicvoid onCompletion(MediaPlayer arg0) {  
  14.       mediaPlayer.release();  
  15.         }  
  16. });  
  17. mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
    // 錯誤處理事件
  18.          @Overridepublicboolean onError(MediaPlayer player, int arg1, int arg2) {  
  19.   mediaPlayer.release();  
  20.   returnfalse;  
  21.          }  
  22. });  
 
  • 程式示例:
[java] view plaincopyprint?
  1. /** 
  2.  * 音訊播放器 
  3.  * @author kay 
  4.  */
  5. publicclass PlayActivity extends Activity   
  6. {  
  7.     privatestaticfinal String TAG = "PlayActivity";  
  8.     private EditText filenameText;  
  9.     private MediaPlayer mediaPlayer;  
  10.     private String filename;  
  11.     privateint position;  
  12.     @Override
  13.     publicvoid onCreate(Bundle savedInstanceState)   
  14.     {  
  15.         super.onCreate(savedInstanceState);  
  16.         setContentView(R.layout.main);  
  17.         filenameText = (EditText)this.findViewById(R.id.filename);  
  18.         //對mediaPlayer進行例項化
  19.         mediaPlayer = new MediaPlayer();  
  20.         ButtonClickListener listener = new ButtonClickListener();  
  21.         //獲取4個按鈕
  22.         Button playButton = (Button)this.findViewById(R.id.play);  
  23.         Button pauseButton = (Button)this.findViewById(R.id.pause);  
  24.         Button resetButton = (Button)this.findViewById(R.id.reset);  
  25.         Button stopButton = (Button) this.findViewById(R.id.stop);  
  26.         //設定4個按鈕的監聽
  27.         playButton.setOnClickListener(listener);  
  28.         pauseButton.setOnClickListener(listener);  
  29.         resetButton.setOnClickListener(listener);  
  30.         stopButton.setOnClickListener(listener);  
  31.         Log.i(TAG, "onCreate()");  
  32.     }  
  33.     @Override
  34.     protectedvoid onRestoreInstanceState(Bundle savedInstanceState)   
  35.     {  
  36.         this.filename = savedInstanceState.getString("filename");  
  37.         this.position = savedInstanceState.getInt("position");  
  38.         super.onRestoreInstanceState(savedInstanceState);  
  39.         Log.i(TAG, "onRestoreInstanceState()");  
  40.     }  
  41.     @Override
  42.     protectedvoid onSaveInstanceState(Bundle outState)   
  43.     {  
  44.         outState.putString("filename", filename);  
  45.         outState.putInt("position", position);  
  46.         super.onSaveInstanceState(outState);  
  47.         Log.i(TAG, "onSaveInstanceState()");  
  48.     }  
  49.     privatevoid play() throws IOException   
  50.     {  
  51.         //獲取檔案路徑
  52.         File audioFile = new File(Environment.getExternalStorageDirectory(),filename);  
  53.         mediaPlayer.reset();  
  54.         mediaPlayer.setDataSource(audioFile.getAbsolutePath());  
  55.         mediaPlayer.prepare();  
  56.         mediaPlayer.start();  
  57.     }  
  58.     //如果突然電話到來,停止播放音樂
  59.     @Override
  60.     protectedvoid onPause()   
  61.     {  
  62.         if(mediaPlayer.isPlaying())  
  63.         {  
  64.             //儲存當前播放點
  65.             position = mediaPlayer.getCurrentPosition();  
  66.             mediaPlayer.stop();  
  67.         }  
  68.         super.onPause();  
  69.     }  
  70.     //
  71.     @Override
  72.     protectedvoid onResume()   
  73.     {  
  74.         //如果電話結束,繼續播放音樂
  75.         if(position>0 && filename!=null)  
  76.         {  
  77.             try
  78.             {  
  79.                 play();  
  80.                 mediaPlayer.seekTo(position);  
  81.                 position = 0;  
  82.             }  
  83.             catch (IOException e)  
  84.             {  
  85.                 Log.e(TAG, e.toString());  
  86.             }  
  87.         }  
  88.         super.onResume();  
  89.     }  
  90.     //對mediaPlayer進行摧毀
  91.     @Override
  92.     protectedvoid onDestroy()   
  93.     {  
  94.         mediaPlayer.release();       
  95.         super.onDestroy();  
  96.         Log.i(TAG, "onDestroy()");  
  97.     }  
  98.     privatefinalclass ButtonClickListener implements View.OnClickListener  
  99.     {  
  100.         @Override
  101.         publicvoid onClick(View v)   
  102.         {  
  103.             //先得到文字框中的內容
  104.             filename = filenameText.getText().toString();  
  105.             //得到button
  106.             Button button = (Button) v;   
  107.             try
  108.             {  
  109.                 //通過傳過來的Buttonid可以判斷Button的型別
  110.                 switch (v.getId())   
  111.                 {  
  112.                     case R.id.play:  
  113.                         play();  
  114.                         break;  
  115.                     case R.id.pause:  
  116.                         if(mediaPlayer.isPlaying())  
  117.                         {  
  118.                             mediaPlayer.pause();  
  119.                             button.setText(R.string.continue1);//讓這個按鈕上的文字顯示為繼續
  120.                         }  
  121.                         else
  122.                         {  
  123.                             mediaPlayer.start();//繼續播放
  124.                             button.setText(R.string.pause);  
  125.                         }  
  126.                         break;  
  127.                     case R.id.reset:  
  128.                         if(mediaPlayer.isPlaying())  
  129.                         {  
  130.                             mediaPlayer.seekTo(0);//讓它從0開始播放
  131.                         }  
  132.                         else
  133.                         {  
  134.                             play();//如果它沒有播放,就讓它開始播放
  135.                         }  
  136.                         break;  
  137.                     case R.id.stop:  
  138.                         //如果它正在播放的話,就讓他停止
  139.                         if(mediaPlayer.isPlaying())   
  140.                             mediaPlayer.stop();  
  141.                         break;  
  142.                 }  
  143.             }   
  144.             catch (Exception e)  
  145.             {     
  146.                 Log.e(TAG, e.toString());  
  147.             }  
  148.         }         
  149.     }     
  150. }  
 

【2】使用SoundPool實現短促的音效

     在Android開發中我們經常使用MediaPlayer來播放音訊檔案,但是MediaPlayer存在一些不足,例如:資源佔用量較高、延遲時間較長、不支援多個音訊同時播放等。這些缺點決定了MediaPlayer在某些場合的使用情況不會很理想,例如在對時間精準度要求相對較高的遊戲開發中。

在遊戲開發中我們經常需要播放一些遊戲音效(比如:子彈爆炸,物體撞擊等),這些音效的共同特點是短促、密集、延遲程度小。在這樣的場景下,我們可以使用SoundPool代替MediaPlayer來播放這些音效。 

    SoundPoolandroid.media.SoundPool),顧名思義是聲音池的意思,主要用於播放一些較短的聲音片段,支援從程式的資源或檔案系統載入。與MediaPlayer相比,SoundPool的優勢在於CPU資源佔用量低和反應延遲小。另外,SoundPool還支援自行設定聲音的品質、音量、播放比率等引數,支援通過ID對多個音訊流進行管理。

  • SoundPool存在的缺陷

1.SoundPool最大隻能申請1M的記憶體空間,這就意味著我們只能用一些很短的聲音片段,而不是用它來播放歌曲或者做遊戲背景音樂。

2.SoundPool提供了pausestop方法,但這些方法建議最好不要輕易使用,因為有些時候它們可能會使你的程式莫名其妙的終止。建議使用這兩個方法的時候儘可能多做測試工作,還有些朋友反映它們不會立即中止播放聲音,而是把緩衝區裡的資料播放完才會停下來,也許會多播放一秒鐘。

3.SoundPool的效率問題。其實SoundPool的效率在這些播放類中算是很好的了,但是有的朋友在G1中測試它還是有100ms左右的延遲,這可能會影響使用者體驗。也許這不能管SoundPool本身,因為到了效能比較好的Droid中這個延遲就可以讓人接受了。

  在現階段SoundPool有這些缺陷,但也有著它不可替代的優點,基於這些我們建議大在如下情況中多使用SoundPool1.應用程式中的聲效(按鍵提示音,訊息等)2.遊戲中密集而短暫的聲音(如多個飛船同時爆炸)

  • SoundPool使用方法

開發步驟:

1>往專案的res/raw目錄中放入音效檔案。

2>新建SoundPool物件,然後呼叫SoundPool.load()載入音效,呼叫SoundPool.play()方法播放指定音效檔案。

[java] view plaincopyprint?
  1. publicclass AudioActivity extends Activity   
  2. {  
  3.     private SoundPool pool;  
  4.     @Override
  5.     publicvoid onCreate(Bundle savedInstanceState)   
  6.     {  
  7.         super.onCreate(savedInstanceState);  
  8.         setContentView(R.layout.main);  
  9.         //指定聲音池的最大音訊流數目為10,聲音品質為5
  10.         pool = new SoundPool(10, AudioManager.STREAM_SYSTEM, 5);  
  11.         //載入音訊流,返回在池中的id
  12.         finalint sourceid = pool.load(this, R.raw.pj, 0);  
  13.         Button button = (Button)this.findViewById(R.id.button);  
  14.         button.setOnClickListener(new View.OnClickListener()   
  15.         {  
  16.             publicvoid onClick(View v)   
  17.             {                               //播放音訊,第二個引數為左聲道音量;第三個引數為右聲道音量;第四個引數為優先順序;第五個引數為迴圈次數,0不迴圈,-1迴圈;第六個引數為速率,速率    最低0.5最高為2,1代表正常速度
  18.                 pool.play(sourceid, 110, -11);  
  19.             }  
  20.         });  
  21.     }  

  22. 注意:
  23. 如果SoundPool剛調完載入load函式之後,直接呼叫SoundPool的play函式可能出現
  24. error "sample 1 not READY"
  25. 所以建議,呼叫載入資源函式load之後,實現資源載入結束的監聽函式,在這個監聽到資源載入結束之後,播放音訊檔案。
  26. 如:
  27.      SoundPool soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 5);
          //載入音訊流,返回在池中的id  
          final int sourceid = soundPool.load(mContext, R.raw.move_sound, 0);
          //播放音訊,第二個引數為左聲道音量;第三個引數為右聲道音量;第四個引數為優先順序;第五個引數為迴圈次數,0不迴圈,-1迴圈;第六個引數為速率,速率最低0.5最高為2,1代表正常速度  
         soundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
                  
               public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                        // TODO Auto-generated method stub
                        soundPool.play(sourceid, 2, 2, 0, 0, 1);
                       }
         });