Android之 MediaPlayer播放一般音訊與SoundPool播放短促的音效
- MediaPlayer播放通常的音訊檔案
- MediaPlayer mediaPlayer = new MediaPlayer();
- if (mediaPlayer.isPlaying()) {
- mediaPlayer.reset();//重置為初始狀態
- }
- mediaPlayer.setDataSource("/mnt/sdcard/god.mp3");
- mediaPlayer.prepare();//緩衝
- mediaPlayer.start();//開始或恢復播放
- mediaPlayer.pause();//暫停播放
- mediaPlayer.start();//恢復播放
- mediaPlayer.stop();//停止播放
- mediaPlayer.release();//釋放資源
- mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {//播出完畢事件
- @Overridepublicvoid onCompletion(MediaPlayer arg0) {
- mediaPlayer.release();
- }
- });
- mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
- @Overridepublicboolean onError(MediaPlayer player, int arg1, int arg2) {
- mediaPlayer.release();
- returnfalse;
- }
- });
- 程式示例:
- /**
- * 音訊播放器
- * @author kay
- */
- publicclass PlayActivity extends Activity
- {
- privatestaticfinal String TAG = "PlayActivity";
- private EditText filenameText;
- private MediaPlayer mediaPlayer;
- private String filename;
- privateint position;
- @Override
- publicvoid onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- filenameText = (EditText)this.findViewById(R.id.filename);
- //對mediaPlayer進行例項化
- mediaPlayer = new MediaPlayer();
- ButtonClickListener listener = new ButtonClickListener();
- //獲取4個按鈕
- Button playButton = (Button)this.findViewById(R.id.play);
- Button pauseButton = (Button)this.findViewById(R.id.pause);
- Button resetButton = (Button)this.findViewById(R.id.reset);
- Button stopButton = (Button) this.findViewById(R.id.stop);
- //設定4個按鈕的監聽
- playButton.setOnClickListener(listener);
- pauseButton.setOnClickListener(listener);
- resetButton.setOnClickListener(listener);
- stopButton.setOnClickListener(listener);
- Log.i(TAG, "onCreate()");
- }
- @Override
- protectedvoid onRestoreInstanceState(Bundle savedInstanceState)
- {
- this.filename = savedInstanceState.getString("filename");
- this.position = savedInstanceState.getInt("position");
- super.onRestoreInstanceState(savedInstanceState);
- Log.i(TAG, "onRestoreInstanceState()");
- }
- @Override
- protectedvoid onSaveInstanceState(Bundle outState)
- {
- outState.putString("filename", filename);
- outState.putInt("position", position);
- super.onSaveInstanceState(outState);
- Log.i(TAG, "onSaveInstanceState()");
- }
- privatevoid play() throws IOException
- {
- //獲取檔案路徑
- File audioFile = new File(Environment.getExternalStorageDirectory(),filename);
- mediaPlayer.reset();
- mediaPlayer.setDataSource(audioFile.getAbsolutePath());
- mediaPlayer.prepare();
- mediaPlayer.start();
- }
- //如果突然電話到來,停止播放音樂
- @Override
- protectedvoid onPause()
- {
- if(mediaPlayer.isPlaying())
- {
- //儲存當前播放點
- position = mediaPlayer.getCurrentPosition();
- mediaPlayer.stop();
- }
- super.onPause();
- }
- //
- @Override
- protectedvoid onResume()
- {
- //如果電話結束,繼續播放音樂
- if(position>0 && filename!=null)
- {
- try
- {
- play();
- mediaPlayer.seekTo(position);
- position = 0;
- }
- catch (IOException e)
- {
- Log.e(TAG, e.toString());
- }
- }
- super.onResume();
- }
- //對mediaPlayer進行摧毀
- @Override
- protectedvoid onDestroy()
- {
- mediaPlayer.release();
- super.onDestroy();
- Log.i(TAG, "onDestroy()");
- }
- privatefinalclass ButtonClickListener implements View.OnClickListener
- {
- @Override
- publicvoid onClick(View v)
- {
- //先得到文字框中的內容
- filename = filenameText.getText().toString();
- //得到button
- Button button = (Button) v;
- try
- {
- //通過傳過來的Buttonid可以判斷Button的型別
- switch (v.getId())
- {
- case R.id.play:
- play();
- break;
- case R.id.pause:
- if(mediaPlayer.isPlaying())
- {
- mediaPlayer.pause();
- button.setText(R.string.continue1);//讓這個按鈕上的文字顯示為繼續
- }
- else
- {
- mediaPlayer.start();//繼續播放
- button.setText(R.string.pause);
- }
- break;
- case R.id.reset:
- if(mediaPlayer.isPlaying())
- {
- mediaPlayer.seekTo(0);//讓它從0開始播放
- }
- else
- {
- play();//如果它沒有播放,就讓它開始播放
- }
- break;
- case R.id.stop:
- //如果它正在播放的話,就讓他停止
- if(mediaPlayer.isPlaying())
- mediaPlayer.stop();
- break;
- }
- }
- catch (Exception e)
- {
- Log.e(TAG, e.toString());
- }
- }
- }
- }
【2】使用SoundPool實現短促的音效
在Android開發中我們經常使用MediaPlayer來播放音訊檔案,但是MediaPlayer存在一些不足,例如:資源佔用量較高、延遲時間較長、不支援多個音訊同時播放等。這些缺點決定了MediaPlayer在某些場合的使用情況不會很理想,例如在對時間精準度要求相對較高的遊戲開發中。
在遊戲開發中我們經常需要播放一些遊戲音效(比如:子彈爆炸,物體撞擊等),這些音效的共同特點是短促、密集、延遲程度小。在這樣的場景下,我們可以使用SoundPool代替MediaPlayer來播放這些音效。
SoundPool(android.media.SoundPool),顧名思義是聲音池的意思,主要用於播放一些較短的聲音片段,支援從程式的資源或檔案系統載入。與MediaPlayer相比,SoundPool的優勢在於CPU資源佔用量低和反應延遲小。另外,SoundPool還支援自行設定聲音的品質、音量、播放比率等引數,支援通過ID對多個音訊流進行管理。
- SoundPool存在的缺陷
1.SoundPool最大隻能申請1M的記憶體空間,這就意味著我們只能用一些很短的聲音片段,而不是用它來播放歌曲或者做遊戲背景音樂。
2.SoundPool提供了pause和stop方法,但這些方法建議最好不要輕易使用,因為有些時候它們可能會使你的程式莫名其妙的終止。建議使用這兩個方法的時候儘可能多做測試工作,還有些朋友反映它們不會立即中止播放聲音,而是把緩衝區裡的資料播放完才會停下來,也許會多播放一秒鐘。
3.SoundPool的效率問題。其實SoundPool的效率在這些播放類中算是很好的了,但是有的朋友在G1中測試它還是有100ms左右的延遲,這可能會影響使用者體驗。也許這不能管SoundPool本身,因為到了效能比較好的Droid中這個延遲就可以讓人接受了。
在現階段SoundPool有這些缺陷,但也有著它不可替代的優點,基於這些我們建議大在如下情況中多使用SoundPool:1.應用程式中的聲效(按鍵提示音,訊息等)2.遊戲中密集而短暫的聲音(如多個飛船同時爆炸)
- SoundPool使用方法
開發步驟:
1>往專案的res/raw目錄中放入音效檔案。
2>新建SoundPool物件,然後呼叫SoundPool.load()載入音效,呼叫SoundPool.play()方法播放指定音效檔案。
[java] view plaincopyprint?- publicclass AudioActivity extends Activity
- {
- private SoundPool pool;
- @Override
- publicvoid onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- //指定聲音池的最大音訊流數目為10,聲音品質為5
- pool = new SoundPool(10, AudioManager.STREAM_SYSTEM, 5);
- //載入音訊流,返回在池中的id
- finalint sourceid = pool.load(this, R.raw.pj, 0);
- Button button = (Button)this.findViewById(R.id.button);
- button.setOnClickListener(new View.OnClickListener()
- {
- publicvoid onClick(View v)
- { //播放音訊,第二個引數為左聲道音量;第三個引數為右聲道音量;第四個引數為優先順序;第五個引數為迴圈次數,0不迴圈,-1迴圈;第六個引數為速率,速率 最低0.5最高為2,1代表正常速度
- pool.play(sourceid, 1, 1, 0, -1, 1);
- }
- });
- }
- }
- 注意:
- 如果SoundPool剛調完載入load函式之後,直接呼叫SoundPool的play函式可能出現
- error "sample 1 not READY"
- 所以建議,呼叫載入資源函式load之後,實現資源載入結束的監聽函式,在這個監聽到資源載入結束之後,播放音訊檔案。
- 如:
- 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);
}
});