在Android開發中我們經常使用MediaPlayer來播放音頻文件。
MediaPlayer的使用方法如下:
//聲明MediaPlayer
MediaPlayer mediaPlayer=null;
指定音頻的源,這裏會有兩種情況,一種是音樂文件在應用中,一種是音樂文件在SD卡中
一、當音樂文件在應用中時,使用create來創建
mediaPlayer =MediaPlayer.create(MainActivity.this, R.raw.audio);
二、當音樂文件在SD卡中時
mediaPlayer=new MediaPlayer();
mediaPlayer.setDataSource(文件路徑);
指定完要播放的文件後,要調用Prepare()
mediaPlayer.Prepare();
//開始播放音樂,在播放前可以判斷一下當前是否已經在播放用isPlaying
mediaPlayer.Start();
//暫停播放音樂
mediaPlayer.Pause();
//重置音樂
mediaPlayer.reset();
但是MediaPlayer存在一些不足,例如:資源佔用量較高、延遲時間較長、不支持多個音頻同時播放等。這些缺點決定了MediaPlayer在某些場合的使用情況不會很理想,例如在對時間精準度要求相對較高的遊戲開發中。在遊戲開發中我們經常需要播放一些遊戲音效(比如:子彈爆炸,物體撞擊等),這些音效的共同特點是短促、密集、延遲程度小。在這樣的場景下,我們可以使用SoundPool代替MediaPlayer來播放這些音效。
1. SoundPool載入音樂文件使用了獨立的線程,不會阻塞UI主線程的操作。但是這裏如果音效文件過大沒有載入完成,我們調用play方法時可能產生嚴重的後果,這裏Android SDK提供了一個SoundPool.OnLoadCompleteListener類來幫助我們瞭解媒體文件是否載入完成,我們重載 onLoadComplete(SoundPool soundPool, int sampleId, int status) 方法即可獲得。
2. 從上面的onLoadComplete方法可以看出該類有很多參數,比如類似id,是的SoundPool在load時可以處理多個媒體一次初始化並放入內存中,這裏效率比MediaPlayer高了很多。
3. SoundPool類支持同時播放多個音效,這對於遊戲來說是十分必要的,而MediaPlayer類是同步執行的只能一個文件一個文件的播放。
SoundPool的使用方法如下:
SoundPool的使用步驟是 :
1.在res中新建raw文件夾,然後將需要播放的音頻放入其中;
2.初始化SoundPool實例;
3.調用SoundPool的play函數進行播放。
4.調用SoundPool的Pause函數進行暫停。
1.幾個重要的函數:
soundPool的構造函數
public SoundPool (int maxStreams, int streamType, int srcQuality)
參數:
maxStream —— 同時播放的流的最大數量
streamType —— 流的類型,一般爲STREAM_MUSIC(具體在AudioManager類中列出)
srcQuality —— 採樣率轉化質量,當前無效果,使用0作爲默認值
例如:
SoundPool soundPool = new SoundPool(3, AudioManager.STREAM_MUSIC, 0);
創建了一個最多支持3個流同時播放的,類型標記爲音樂的SoundPool。
2.一般把多個聲音放到HashMap中去
比如
soundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 100);
soundPoolMap = new HashMap<Integer, Integer>();
soundPoolMap.put(1, soundPool.load(this, R.raw.dingdong, 1));
soundpool的加載:
int load(Context context, int resId, int priority) //從APK資源載入
int load(FileDescriptor fd, long offset, long length, int priority) //從FileDescriptor對象載入
int load(AssetFileDescriptor afd, int priority) //從Asset對象載入
int load(String path, int priority) //從完整文件路徑名載入
最後一個參數爲優先級。
3.創建音效播放函數用來播放音樂文件:
public void playSounds(int sound, int number){
//實例化AudioManager對象,控制聲音
AudioManager am = (AudioManager)this.getSystemService(this.AUDIO_SERVICE);
//最大音量
float audioMaxVolumn =am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
//當前音量
float audioCurrentVolumn = am.getStreamVolume(AudioManager.STREAM_MUSIC);
float volumnRatio = audioCurrentVolumn/audioMaxVolumn;
//播放
sp.play(spMap.get(sound), //聲音資源
volumnRatio, //左聲道
volumnRatio, //右聲道
1, //優先級,0最低
number, //循環次數,0是不循環,-1是永遠循環
1); //回放速度,0.5-2.0之間。1爲正常速度
}
4.暫停
暫停可以使用 pause(int streamID) 方法,這裏的streamID和soundID均在構造SoundPool類的第一個參數中指明瞭總數量,而id從0開始。
pause按鈕在第一次播放的時候好用,第一次之後的播放就不管用了,網上找到的解釋:
原來這個流對應的ID是需要play方法返回的,後來我用mPresentPlayId存儲play返回的流ID,在stop時將流ID使用mPresentPlayId來替換就沒問題了,後來輸出了下mPresentPlayId的值,發現這個值第一次是2.第二次是4,以後使用這個方法一定要注意這個問題。
具體代碼實現如下:
import java.io.IOException;
import java.util.HashMap;
import android.R.anim;
import android.R.integer;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.SoundPool;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
public class MainActivity extends Activity
{
Button btn_MediaPlayerStart = null;
Button btn_MediaPlayerPause=null;
Button btn_SoundPoolStart=null;
Button btn_SoundPoolPause=null;
MediaPlayer mp = null;
SoundPool soundPool=null;
int soundPoolPlayId=0;
HashMap<Integer, Integer> SoundPoolMap =null;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
initSounds();
setContentView(R.layout.activity_main);
btn_MediaPlayerStart = (Button) findViewById(R.id.btn_MediaPlayerStart);
btn_MediaPlayerPause=(Button)findViewById(R.id.btn_MediaPlayerPause);
btn_SoundPoolStart=(Button)findViewById(R.id.btn_SoundPoolStart);
btn_SoundPoolPause=(Button)findViewById(R.id.btn_SoundPoolSPause);
btn_MediaPlayerStart.setOnClickListener(buttonClickListener);
btn_MediaPlayerPause.setOnClickListener(buttonClickListener);
btn_SoundPoolStart.setOnClickListener(buttonClickListener);
btn_SoundPoolPause.setOnClickListener(buttonClickListener);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
//用於初始化mediaPlayer和soundPool聲音
public void initSounds()
{
mp = MediaPlayer.create(MainActivity.this, R.raw.audio);
soundPool=new SoundPool(4,AudioManager.STREAM_MUSIC,100);
SoundPoolMap=new HashMap<Integer, Integer>();
SoundPoolMap.put(1, soundPool.load(this,R.raw.global,1));
}
//創建了一個方法,用來開始播放soundPool聲音
public void playSound(int sound,int loop)
{
AudioManager mgr=(AudioManager)this.getSystemService(Context.AUDIO_SERVICE);
float streamVolumeCurrent=mgr.getStreamVolume(AudioManager.STREAM_MUSIC);
float streamVolumeMax=mgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
float volume=streamVolumeCurrent/streamVolumeMax;
soundPoolPlayId=soundPool.play(SoundPoolMap.get(sound), volume, volume, 1, loop, 1f);
}
private OnClickListener buttonClickListener = new OnClickListener()
{
@Override
public void onClick(View v)
{
//btn_MediaPlayerStart按鈕的單擊事件
if (v == btn_MediaPlayerStart)
{
try
{
mp.prepare();
} catch (IllegalStateException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
if (!mp.isPlaying())
{
mp.start();
}
}
//btn_MediaPlayerPause按鈕的單擊事件
else if(v==btn_MediaPlayerPause)
{
try
{
mp.prepare();
} catch (IllegalStateException e)
{
// TODO 自動生成的 catch 塊
e.printStackTrace();
} catch (IOException e)
{
// TODO 自動生成的 catch 塊
e.printStackTrace();
}
if (mp.isPlaying())
{
mp.pause();
}
}
//btn_SoundPoolStart按鈕的單擊事件
else if(v==btn_SoundPoolStart)
{
playSound(1, 0);
}
//btn_SoundPoolPause按鈕的單擊事件
else if(v==btn_SoundPoolPause)
{
soundPool.pause(soundPoolPlayId);
}
}
};
}