2012年4月1日 星期日

[TQC+ Android] 3-3 MP3 播放器 Use MediaPlayer






設計MP3播放器 , 畫面上顯示三個按鍵 , 由左至右排成一列 , 分別是播放 暫停 停止 , 按鍵上方顯示程式狀態 , 這題除了基本的初始化MediaPlayer資源之外就是流程控制了, 另外程式也註冊了當MediaPlayer播放完畢和發生錯誤的Listener事件 , 一開始附上了一張MediaPlayer從初始化到釋放資源的流程控制狀態圖 ,  另外請先載入檔案至res/raw 資料夾底下, 以下是程式碼。




package COM.TQC.GDD03;


import android.app.Activity; 
import android.media.AudioManager;
import android.media.MediaPlayer; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.ImageButton;
import android.widget.TextView; 


public class GDD03 extends Activity
{   
   private ImageButton mButtonPlay, mButtonPause, mButtonStop;
   private TextView mTextView; 
   private MediaPlayer mMediaPlayer;
   private boolean bIsPaused = false; 
   
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        //透過findViewById建構子建立TextView與ImageView物件 
       
        mTextView = (TextView) this.findViewById(R.id.textView1);
        mButtonPlay = (ImageButton) this.findViewById(R.id.imageButton1);
        mButtonPause = (ImageButton) this.findViewById(R.id.imageButton2);
        mButtonStop = (ImageButton) this.findViewById(R.id.imageButton3);
        
        mButtonStop.setEnabled(false);  
        mButtonPause.setEnabled(false);
        //一開始將Stop和Pause按鈕都diable, 只允許Play按鈕enable
                 

        // 執行播放音樂的按鈕  
        mButtonPlay.setOnClickListener(new ImageButton.OnClickListener() 
        { 
          //覆寫OnClick事件
          public void onClick(View v) 
          { 
            // TODO Auto-generated method stub         
            try 
            { 
             //判斷是否由暫停狀態開始播放
             if(!bIsPaused)
             {              
              ini();
              //將音樂以Import的方式儲存在res/raw/always.mp3
              //目前狀態為Stop狀態, 由於Stop狀態會release Media, 所以要再額外重新ini() Media 一次 
             }
             
            } 
            catch (Exception e) 
            { 
              // TODO Auto-generated catch block              
              e.printStackTrace(); 
            } 
            finally
            { 
             mMediaPlayer.start();
             //撥放音樂
             
             mTextView.setText(getText(R.string.str_start));
             mButtonPlay.setEnabled(false);
                mButtonPause.setEnabled(true);
                mButtonStop.setEnabled(true);
                //當音樂播放時, enable Pause和Stop按鈕, disable Play按鈕
            }
          } 
        }); 
         
        // 停止播放 
        mButtonStop.setOnClickListener(new ImageButton.OnClickListener() 
        { 
         // @Override
          public void onClick(View arg0) 
          { 
            // TODO Auto-generated method stub 
            try 
            { 
              if (mMediaPlayer != null) 
              { 
               bIsPaused = false;
               mMediaPlayer.stop();
               mMediaPlayer.release();               
               //將Media 資源 release
               
               mTextView.setText(getText(R.string.str_close));
                 mButtonPlay.setEnabled(true);
                  mButtonPause.setEnabled(false);
                  mButtonStop.setEnabled(false);
                  //當停止播放時, disable Pause和Stop按鈕, enable Play按鈕
                  
              }                 
            } 
            catch (Exception e) 
            { 
              // TODO Auto-generated catch block              
              e.printStackTrace(); 
            } 
          } 
        }); 
        
        // 暫停播放  
        mButtonPause.setOnClickListener(new ImageButton.OnClickListener() 
        { 
          //@Override
          public void onClick(View arg0) 
          { 
            // TODO Auto-generated method stub 
            pauseMedia();
          }
        });      
        
         
      } 
    
      //初始建立Media 資源
      public void ini()
      {
       mMediaPlayer = MediaPlayer.create(GDD03.this, R.raw.always);
                 
       mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
       
       //mMediaPlayer.prepare();          
         //特別使用註解的方式, 是為了提醒大家, 由於我們先前使用create method建立MediaPlayer
         //create method會自動的call prepare(), 所以我們再call prepare() method會發生 prepareAsync called in state 8的錯誤
                  
  
  //當MediaPlayer.OnCompletionLister會執行的Listener            
        mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() 
        { 
          @Override 
          
          //覆寫檔案播出完畢事件
          public void onCompletion(MediaPlayer arg0) 
          { 
            try 
            {  
             bIsPaused = true;
             mTextView.setText("音樂播完了");
             mButtonPlay.setEnabled(true);
                mButtonPause.setEnabled(false);
                mButtonStop.setEnabled(false);
                //當音樂播放完畢時, disable Pause和Stop按鈕, enable Play按鈕
            
            } 
            catch (Exception e) 
            { 
              mTextView.setText(e.toString()); 
              e.printStackTrace(); 
            } 
          } 
        }); 
         
        //當MediaPlayer.OnErrorListener會執行的Listener 
        mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() 
        { 
          @Override //p530
          //覆寫錯誤處理事件
          public boolean onError(MediaPlayer arg0, int arg1, int arg2) 
          { 
            // TODO Auto-generated method stub 
            try 
            {
               
                // arg1為error code分別為,
                // 分別為MEDIA_ERROR_UNKNOWN(1): Unspecified media player error.
                // MEDIA_ERROR_SERVER_DIED(100): Media server died. In this case, the application must release the MediaPlayer object and instantiate a new one.
             // arg2為extra code , an extra code, specific to the error. Typically implementation dependant.
                
             mMediaPlayer.release();
             bIsPaused = false;
            } 
            catch (Exception e) 
            { 
              mTextView.setText("Error Code:"+arg1+" Extra Code:"+arg2+" Error Msg:"+e.toString()); 
              e.printStackTrace(); 
            } 
            return false; 
          } 
        });  
      }
      
      public void pauseMedia()
      {  
       try 
          {          
        bIsPaused = true;
        mMediaPlayer.pause();
             //暫停播放
             mTextView.setText(getText(R.string.str_pause));
             mButtonPlay.setEnabled(true);
              mButtonPause.setEnabled(false);
              mButtonStop.setEnabled(true);
              //當暫停播放時, disable Pause按鈕, enable Play和Stop按鈕                
          } 
          catch (Exception e) 
          { 
            mTextView.setText(e.toString()); 
            e.printStackTrace(); 
          }       
      }

      @Override 
      //覆寫主程式暫停狀態事件
      protected void onPause() 
      { 
        // TODO Auto-generated method stub
        super.onPause();
        pauseMedia();
        //當程式突然因為某些因素被迫中斷例如來電 , 我們會需要將音樂自動暫停
        
      }       
    } 


在這邊要特別無論是在官方的開發文件或是許多教材都提到 , 在start() MediaPlayer之前必須call prepare() method , 讓MediaPlayer物件進入 Prepared state , 但是請注意 ! 如果是使用static  MediaPlayer.create() 這個method 建立MediaPlayer資源的話, 這個method會自動的去call prepare() method , 如果這時候還是在start()之前去call prepare()的話會發生 prepareAsync called in state 8的錯誤。




再來是Layout檔的部分

    
    
    
    



在main.xml文件中 , 已經把三個ImageButton的圖片來源都設定好了。












P.S. 題目中所要求的Variable和Method皆會保留 , 也會根據題目所要求的流程去實作 , 縱使題目要求繞遠路....





沒有留言:

張貼留言

Google Analytics