Android游戲開發(fā)之十五:如何實(shí)現(xiàn)異步音樂播放
作者:佚名
在Android游戲開發(fā)中我們必須考慮背景音樂播放問題,在Android平臺(tái)中提供了MediaPlayer類可以播放聲音,但是游戲除了播放音樂外還需要考慮畫面的流暢性,以及多種音效同時(shí)播放,所以必須用到Android多線程機(jī)制和異步音效播放。Android SDK從1.0開始就提供了AsyncPlayer類,這里我們?yōu)榱烁鶕?jù)我們自己的需要可以派生或修改出更靈活的播放類。
進(jìn)行Android游戲開發(fā)時(shí),背景音樂的播放幾乎是不得不考慮的問題,Android SDK提供了MediaPlayer類來播放聲音,但還要充分考慮到它與畫面的協(xié)調(diào),畫面的流暢性,多種音效同時(shí)播放等問題,這樣就必須使用Android多線程機(jī)制和異步音樂播放。
從Android SDK 1.0開始就提供了AsyncPlayer類,我們?cè)谑褂盟鼤r(shí)可以根據(jù)需要派生出子類,以更靈活的實(shí)現(xiàn)異步播放功能。
- import android.content.Context;
- import android.net.Uri;
- import android.os.PowerManager;
- import android.os.SystemClock;
- import android.util.Log;
- import java.io.IOException;
- import java.lang.IllegalStateException;
- import java.util.LinkedList;
- public class AsyncPlayer {
- private static final int PLAY = 1;
- private static final int STOP = 2;
- private static final boolean mDebug = false;
- private static final class Command {
- int code;
- Context context;
- Uri uri;
- boolean looping;
- int stream;
- long requestTime;
- public String toString() {
- return "{ code=" + code + " looping=" + looping + " stream=" + stream
- + " uri=" + uri + " }";
- }
- }
- private LinkedList<Command> mCmdQueue = new LinkedList(); //用一個(gè)鏈表保存播放參數(shù)隊(duì)列
- private void startSound(Command cmd) {
- try {
- MediaPlayer player = new MediaPlayer();
- player.setAudioStreamType(cmd.stream);
- player.setDataSource(cmd.context, cmd.uri); //設(shè)置媒體源,這里Android123提示大家本類的public void play (Context context, Uri uri, boolean looping, int stream) 類第二個(gè)參數(shù)Uri為媒體位置。
- player.setLooping(cmd.looping);
- player.prepare();
- player.start();
- if (mPlayer != null) {
- mPlayer.release();
- }
- mPlayer = player;
- }
- catch (IOException e) {
- Log.w(mTag, "error loading sound for " + cmd.uri, e);
- } catch (IllegalStateException e) {
- Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e);
- }
- }
- private final class Thread extends java.lang.Thread { //通過多線程方式不阻塞調(diào)用者
- Thread() {
- super("AsyncPlayer-" + mTag);
- }
- public void run() {
- while (true) {
- Command cmd = null;
- synchronized (mCmdQueue) { //同步方式執(zhí)行
- cmd = mCmdQueue.removeFirst();
- }
- switch (cmd.code) {
- case PLAY:
- startSound(cmd);
- break;
- case STOP:
- if (mPlayer != null) {
- mPlayer.stop();
- mPlayer.release();
- mPlayer = null;
- } else {
- Log.w(mTag, "STOP command without a player");
- }
- break;
- }
- synchronized (mCmdQueue) {
- if (mCmdQueue.size() == 0) {
- mThread = null;
- releaseWakeLock();
- return;
- }
- }
- }
- }
- }
- private String mTag;
- private Thread mThread;
- private MediaPlayer mPlayer;
- private PowerManager.WakeLock mWakeLock;
- private int mState = STOP;
- public AsyncPlayer(String tag) {
- if (tag != null) {
- mTag = tag;
- } else {
- mTag = "AsyncPlayer";
- }
- }
- public void play(Context context, Uri uri, boolean looping, int stream) {
- Command cmd = new Command();
- cmd.requestTime = SystemClock.uptimeMillis(); //這里為了測(cè)試性能,傳遞了開始執(zhí)行前的系統(tǒng)tickcount計(jì)時(shí)器值
- cmd.code = PLAY;
- cmd.context = context;
- cmd.uri = uri;
- cmd.looping = looping;
- cmd.stream = stream;
- synchronized (mCmdQueue) {
- enqueueLocked(cmd);
- mState = PLAY;
- }
- }
- public void stop() {
- synchronized (mCmdQueue) {
- if (mState != STOP) {
- Command cmd = new Command();
- cmd.requestTime = SystemClock.uptimeMillis();
- cmd.code = STOP;
- enqueueLocked(cmd);
- mState = STOP;
- }
- }
- }
- private void enqueueLocked(Command cmd) {
- mCmdQueue.add(cmd);
- if (mThread == null) {
- acquireWakeLock();
- mThread = new Thread();
- mThread.start();
- }
- }
- // 一般對(duì)于Android游戲而言下面的代碼不用考慮,一般用戶都在交互操作,不會(huì)出現(xiàn)屏幕鎖問題
- public void setUsesWakeLock(Context context) { //電源管理wakelock處理
- if (mWakeLock != null || mThread != null) {
- throw new RuntimeException("assertion failed mWakeLock=" + mWakeLock
- + " mThread=" + mThread);
- }
- PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);
- }
- private void acquireWakeLock() { //加鎖
- if (mWakeLock != null) {
- mWakeLock.acquire();
- }
- }
- private void releaseWakeLock() { //解鎖
- if (mWakeLock != null) {
- mWakeLock.release();
- }
- }
- }
責(zé)任編輯:閆佳明
來源:
jizhuomi