Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android多媒體開發 音樂播放(加帶進度條、時間顯示)以及使用SoundPool播放音效

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

編輯:關於Android編程

音樂播放

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;

	@Override
	public 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 stub
					mediaPlayer.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 {

		@Override
		public 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;

	@Override
	public 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
	}
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved