Android多媒體開發 音樂播放(加帶進度條、時間顯示)以及使用SoundPool播放音效

來源:互聯網
上載者:User

音樂播放

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() {//播出完畢事件
@Override public void onCompletion(MediaPlayer arg0) {
mediaPlayer.release();
}
});
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {// 錯誤處理事件
@Override public boolean onError(MediaPlayer player, int arg1, int arg2) {
mediaPlayer.release();
return false;
}

});

音樂播放程式碼範例:DemoActivity.java:
package cn.itcast.mp3;import java.io.File;import android.app.Activity;import android.media.MediaPlayer;import android.media.MediaPlayer.OnCompletionListener;import android.media.MediaPlayer.OnPreparedListener;import android.os.Bundle;import android.os.Handler;import android.os.SystemClock;import android.telephony.PhoneStateListener;import android.telephony.TelephonyManager;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.Chronometer;import android.widget.Chronometer.OnChronometerTickListener;import android.widget.EditText;import android.widget.SeekBar;import android.widget.SeekBar.OnSeekBarChangeListener;import android.widget.Toast;public class DemoActivity extends Activity implements OnClickListener,OnChronometerTickListener, OnSeekBarChangeListener {private EditText et_path;private Chronometer et_time;private SeekBar sb;private Button bt_play, bt_pause, bt_replay, bt_stop;private MediaPlayer mediaPlayer;private TelephonyManager manager;/** * subtime:點擊“續播”到暫停時的間隔的和 beginTime:重新回到播放時的bash值 falgTime:點擊“播放”時的值 * pauseTime:“暫停”時的值 */private long subtime = 0, beginTime = 0, falgTime = 0, pauseTime = 0;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);manager = (TelephonyManager) this.getSystemService(TELEPHONY_SERVICE);manager.listen(new MyListener(), PhoneStateListener.LISTEN_CALL_STATE);sb = (SeekBar) this.findViewById(R.id.sb);et_path = (EditText) this.findViewById(R.id.et_path);et_time = (Chronometer) this.findViewById(R.id.et_time);bt_play = (Button) this.findViewById(R.id.play);bt_pause = (Button) this.findViewById(R.id.pause);bt_replay = (Button) this.findViewById(R.id.replay);bt_stop = (Button) this.findViewById(R.id.stop);sb.setEnabled(false);sb.setOnSeekBarChangeListener(this);bt_play.setOnClickListener(this);bt_pause.setOnClickListener(this);bt_replay.setOnClickListener(this);bt_stop.setOnClickListener(this);et_time.setOnChronometerTickListener(this);}Handler handler = new Handler();Runnable updateThread = new Runnable() {public void run() {// 獲得歌曲現在播放位置並設定成播放進度條的值if (mediaPlayer != null) {sb.setProgress(mediaPlayer.getCurrentPosition());// 每次延遲100毫秒再啟動線程handler.postDelayed(updateThread, 100);}}};public void onClick(View v) {String path;try {switch (v.getId()) {case R.id.play:falgTime = SystemClock.elapsedRealtime();path = et_path.getText().toString().trim();play(path);pauseTime = 0;et_time.setBase(falgTime);et_time.start();break;case R.id.pause:pause();break;case R.id.replay:if (mediaPlayer != null && mediaPlayer.isPlaying()) {mediaPlayer.seekTo(0);et_time.setBase(SystemClock.elapsedRealtime());et_time.start();} else {path = et_path.getText().toString().trim();play(path);et_time.setBase(SystemClock.elapsedRealtime());et_time.start();}if ("續播".equals(bt_pause.getText().toString().trim())) {bt_pause.setText("暫停");}falgTime = SystemClock.elapsedRealtime();subtime = 0;break;case R.id.stop:if (mediaPlayer != null && mediaPlayer.isPlaying()) {mediaPlayer.stop();mediaPlayer = null;et_time.setBase(SystemClock.elapsedRealtime());et_time.start();et_time.stop();bt_play.setEnabled(true);bt_play.setClickable(true);}falgTime = 0;subtime = 0;sb.setProgress(0);sb.setEnabled(false);break;}} catch (Exception e) {e.printStackTrace();Toast.makeText(getApplicationContext(), "檔案播放出現異常", 0).show();}}private void pause() {// 判斷音樂是否在播放if (mediaPlayer != null && mediaPlayer.isPlaying()) {// 暫停音樂播放器mediaPlayer.pause();bt_pause.setText("續播");sb.setEnabled(false);et_time.stop();pauseTime = SystemClock.elapsedRealtime();// System.out.println("1 pauseTime" + pauseTime);} else if (mediaPlayer != null&& "續播".equals(bt_pause.getText().toString())) {subtime += SystemClock.elapsedRealtime() - pauseTime;// System.out.println("2 subtime:" + subtime);mediaPlayer.start();bt_pause.setText("暫停");sb.setEnabled(true);beginTime = falgTime + subtime;// System.out.println("3 beginTime" + beginTime);et_time.setBase(beginTime);et_time.start();}}/** * 播放指定地址的音樂檔案 .mp3 .wav .amr *  * @param path */private void play(String path) throws Exception {if ("".equals(path)) {Toast.makeText(getApplicationContext(), "路徑不可為空", 0).show();return;}File file = new File(path);if (file.exists()) {mediaPlayer = new MediaPlayer();mediaPlayer.setDataSource(path);// mediaPlayer.prepare(); // c/c++ 播放器引擎的初始化// 同步方法// 採用非同步方式mediaPlayer.prepareAsync();// 為播放器註冊mediaPlayer.setOnPreparedListener(new OnPreparedListener() {public void onPrepared(MediaPlayer mp) {// TODO Auto-generated method stubmediaPlayer.start();bt_play.setEnabled(false);bt_play.setClickable(false);sb.setMax(mediaPlayer.getDuration());handler.post(updateThread);sb.setEnabled(true);}});// 註冊播放完畢後的監聽事件mediaPlayer.setOnCompletionListener(new OnCompletionListener() {public void onCompletion(MediaPlayer mp) {mediaPlayer.release();mediaPlayer = null;bt_play.setEnabled(true);bt_play.setClickable(true);et_time.setBase(SystemClock.elapsedRealtime());et_time.start();et_time.stop();sb.setProgress(0);}});} else {Toast.makeText(getApplicationContext(), "檔案不存在", 0).show();return;}}private class MyListener extends PhoneStateListener {@Overridepublic void onCallStateChanged(int state, String incomingNumber) {super.onCallStateChanged(state, incomingNumber);switch (state) {case TelephonyManager.CALL_STATE_RINGING:// 音樂播放器暫停pause();break;case TelephonyManager.CALL_STATE_IDLE:// 重新播放音樂pause();break;}}}public void onChronometerTick(Chronometer chronometer) {}public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {// TODO 自動產生的方法存根if (fromUser == true && mediaPlayer != null) {mediaPlayer.seekTo(progress);falgTime = SystemClock.elapsedRealtime();beginTime = falgTime - sb.getProgress();et_time.setBase(beginTime);et_time.start();}}public void onStartTrackingTouch(SeekBar seekBar) {// TODO 自動產生的方法存根}public void onStopTrackingTouch(SeekBar seekBar) {// TODO 自動產生的方法存根}}
main.xml:
                                                    

使用SoundPool播放音效: 在Android開發中我們經常使用MediaPlayer來播放音頻檔案,但是MediaPlayer存在一些不足,例如:資源佔用量較高、延遲時間較長、不支援多個音頻同時播放等。這些缺點決定了MediaPlayer在某些場合的使用方式不會很理想,例如在對時間精準度要求相對較高的遊戲開發中。
在遊戲開發中我們經常需要播放一些遊戲音效(比如:子彈爆炸,物體撞擊等),這些音效的共同特點是短促、密集、延遲程度小。在這樣的情境下,我們可以使用SoundPool代替MediaPlayer來播放這些音效。
SoundPool(android.media.SoundPool),顧名思義是聲音池的意思,主要用於播放一些較短的聲音片段,支援從程式的資源或檔案系統載入。與MediaPlayer相比,SoundPool的優勢在於CPU資源佔用量低和反應延遲小。另外,SoundPool還支援自行設定聲音的品質、音量、播放比率等參數,支援通過ID對多個音頻流進行管理。
就現在已知的資料來說,SoundPool有一些設計上的BUG,從韌體版本1.0開始有些還沒有修複,我們在使用中應該小心再小心。相信將來Google會修複這些問題,但我們最好還是列出來:
  1. SoundPool最大隻能申請1M的記憶體空間,這就意味著我們只能用一些很短的聲音片段,而不是用它來播放歌曲或者做遊戲背景音樂。
  2. SoundPool提供了pause和stop方法,但這些方法建議最好不要輕易使用,因為有些時候它們可能會使你的程式莫名其妙的終止。建議使用這兩個方法的時候儘可能多做測試工作,還有些朋友反映它們不會立即中止播放聲音,而是把緩衝區裡的資料播放完才會停下來,也許會多播放一秒鐘。
  3. SoundPool的效率問題。其實SoundPool的效率在這些播放類中算是很好的了,但是有的朋友在G1中測試它還是有100ms左右的延遲,這可能會影響使用者體驗。也許這不能管SoundPool本身,因為到了效能比較好的Droid中這個延遲就可以讓人接受了。
  在現階段SoundPool有這些缺陷,但也有著它不可替代的優點,基於這些我們建議大在如下情況中多使用SoundPool: 1.應用程式中的聲效(按鍵提示音,訊息等)2.遊戲中密集而短暫的聲音(如多個飛船同時爆炸)
開發步驟:
1> 往項目的res/raw目錄中放入音效檔案。
2> 建立SoundPool對象,然後調用SoundPool.load()載入音效,調用SoundPool.play()方法播放指定音效檔案。
public class AudioActivity extends Activity {
private SoundPool pool;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//指定聲音池的最大音頻流數目為10,聲音品質為5
pool = new SoundPool(10, AudioManager.STREAM_SYSTEM, 5);
final int sourceid = pool.load(this, R.raw.pj, 0);//載入音頻流,返回在池中的id
Button button = (Button)this.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//播放音頻,第二個參數為左聲道音量;第三個參數為右聲道音量;第四個參數為優先順序;第五個參數為迴圈次數,0不迴圈,-1迴圈;第六個參數為速率,速率最低0.5最高為2,1代表正常速度
pool.play(sourceid, 1, 1, 0, -1, 1);
}
});
}
}

使用SoundPool播放音效程式碼範例:DemoActivity.java:
package cn.itcast.soundpool;import android.app.Activity;import android.media.AudioManager;import android.media.SoundPool;import android.os.Bundle;import android.view.View;public class DemoActivity extends Activity {int soundid;SoundPool pool;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);pool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);// 這語句代碼 是一個非同步操作soundid = pool.load(this, R.raw.ring, 1); // 需要花費一定的時間}public void shoot(View view) {// 不會播放 因為上面非同步載入聲音的操作 還沒完成pool.play(soundid, 1.0f, 1.0f, 0, 0, 1.0f);// taking tom}}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.