Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android游戲 >> Android游戲開發 >> Android游戲開發教程之十五:如何實現異步音樂播放

Android游戲開發教程之十五:如何實現異步音樂播放

編輯:Android游戲開發

       進行Android游戲開發時,背景音樂的播放幾乎是不得不考慮的問題,Android SDK提供了MediaPlayer類來播放聲音,但還要充分考慮到它與畫面的協調,畫面的流暢性,多種音效同時播放等問題,這樣就必須使用Android多線程機制和異步音樂播放。

       從Android SDK 1.0開始就提供了AsyncPlayer類,我們在使用它時可以根據需要派生出子類,以更靈活的實現異步播放功能。

Java代碼
  1. import android.content.Context;   
  2. import android.net.Uri;   
  3. import android.os.PowerManager;   
  4. import android.os.SystemClock;   
  5. import android.util.Log;   
  6.   
  7. import java.io.IOException;   
  8. import java.lang.IllegalStateException;   
  9. import java.util.LinkedList;   
  10.   
  11.     
  12. public class AsyncPlayer {   
  13.     private static final int PLAY = 1;   
  14.     private static final int STOP = 2;   
  15.     private static final boolean mDebug = false;   
  16.   
  17.     private static final class Command {   
  18.         int code;   
  19.         Context context;   
  20.         Uri uri;   
  21.         boolean looping;   
  22.         int stream;   
  23.         long requestTime;   
  24.   
  25.         public String toString() {   
  26.             return "{ code=" + code + " looping=" + looping + " stream=" + stream   
  27.                     + " uri=" + uri + " }";   
  28.         }   
  29.     }   
  30.   
  31.     private LinkedList<Command> mCmdQueue = new LinkedList();  //用一個鏈表保存播放參數隊列   
  32.   
  33.     private void startSound(Command cmd) {   
  34.      
  35.         try {   
  36.             MediaPlayer player = new MediaPlayer();   
  37.             player.setAudioStreamType(cmd.stream);   
  38.             player.setDataSource(cmd.context, cmd.uri);  //設置媒體源,這裡Android123提示大家本類的public void play (Context context, Uri uri, boolean looping, int stream) 類第二個參數Uri為媒體位置。   
  39.             player.setLooping(cmd.looping);   
  40.             player.prepare();   
  41.             player.start();   
  42.             if (mPlayer != null) {   
  43.                 mPlayer.release();   
  44.             }   
  45.             mPlayer = player;   
  46.           }   
  47.         catch (IOException e) {   
  48.             Log.w(mTag, "error loading sound for " + cmd.uri, e);   
  49.         } catch (IllegalStateException e) {   
  50.             Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e);   
  51.         }   
  52.     }   
  53.   
  54.     private final class Thread extends java.lang.Thread {   //通過多線程方式不阻塞調用者   
  55.         Thread() {   
  56.             super("AsyncPlayer-" + mTag);   
  57.         }   
  58.   
  59.         public void run() {   
  60.             while (true) {   
  61.                 Command cmd = null;   
  62.   
  63.                 synchronized (mCmdQueue) {   //同步方式執行   
  64.   
  65.                         cmd = mCmdQueue.removeFirst();   
  66.                 }   
  67.   
  68.                 switch (cmd.code) {   
  69.                 case PLAY:   
  70.                                  startSound(cmd);   
  71.                     break;   
  72.                 case STOP:   
  73.     
  74.                     if (mPlayer != null) {   
  75.                                          mPlayer.stop();   
  76.                         mPlayer.release();   
  77.                         mPlayer = null;   
  78.                     } else {   
  79.                         Log.w(mTag, "STOP command without a player");   
  80.                     }   
  81.                     break;   
  82.                 }   
  83.   
  84.                 synchronized (mCmdQueue) {   
  85.                     if (mCmdQueue.size() == 0) {   
  86.                
  87.                         mThread = null;   
  88.                         releaseWakeLock();   
  89.                         return;   
  90.                     }   
  91.                 }   
  92.             }   
  93.         }   
  94.     }   
  95.   
  96.     private String mTag;   
  97.     private Thread mThread;   
  98.     private MediaPlayer mPlayer;   
  99.     private PowerManager.WakeLock mWakeLock;   
  100.   
  101.     
  102.     private int mState = STOP;   
  103.     
  104.     public AsyncPlayer(String tag) {   
  105.         if (tag != null) {   
  106.             mTag = tag;   
  107.         } else {   
  108.             mTag = "AsyncPlayer";   
  109.         }   
  110.     }   
  111.   
  112.     
  113.     public void play(Context context, Uri uri, boolean looping, int stream) {   
  114.         Command cmd = new Command();   
  115.         cmd.requestTime = SystemClock.uptimeMillis(); //這裡為了測試性能,傳遞了開始執行前的系統tickcount計時器值   
  116.         cmd.code = PLAY;   
  117.         cmd.context = context;   
  118.         cmd.uri = uri;   
  119.         cmd.looping = looping;   
  120.         cmd.stream = stream;   
  121.         synchronized (mCmdQueue) {   
  122.             enqueueLocked(cmd);   
  123.             mState = PLAY;   
  124.         }   
  125.     }   
  126.        
  127.     
  128.     public void stop() {   
  129.         synchronized (mCmdQueue) {   
  130.                  if (mState != STOP) {   
  131.                 Command cmd = new Command();   
  132.                 cmd.requestTime = SystemClock.uptimeMillis();   
  133.                 cmd.code = STOP;   
  134.                 enqueueLocked(cmd);   
  135.                 mState = STOP;   
  136.             }   
  137.         }   
  138.     }   
  139.   
  140.     private void enqueueLocked(Command cmd) {   
  141.         mCmdQueue.add(cmd);   
  142.         if (mThread == null) {   
  143.             acquireWakeLock();   
  144.             mThread = new Thread();   
  145.             mThread.start();   
  146.         }   
  147.     }   
  148.   
  149.     // 一般對於Android游戲而言下面的代碼不用考慮,一般用戶都在交互操作,不會出現屏幕鎖問題   
  150.   
  151.     public void setUsesWakeLock(Context context) {  //電源管理wakelock處理   
  152.         if (mWakeLock != null || mThread != null) {   
  153.                       throw new RuntimeException("assertion failed mWakeLock=" + mWakeLock   
  154.                     + " mThread=" + mThread);   
  155.         }   
  156.         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);   
  157.         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);   
  158.     }   
  159.   
  160.     private void acquireWakeLock() {   //加鎖   
  161.         if (mWakeLock != null) {   
  162.             mWakeLock.acquire();   
  163.         }   
  164.     }   
  165.   
  166.     private void releaseWakeLock() { //解鎖   
  167.         if (mWakeLock != null) {   
  168.             mWakeLock.release();   
  169.         }   
  170.     }   
  171. }  

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved