深入Android MediaPlayer的使用方法詳解

1)如何獲得MediaPlayer實例:
可以使用直接new的方式:
MediaPlayer mp = new MediaPlayer();
也可以使用create的方式,如:
MediaPlayer mp = MediaPlayer.create(this, R.raw.test);//這時就不用調用setDataSource了

2) 如何設置要播放的文件:
MediaPlayer要播放的文件主要包括3個來源:
a. 用戶在應用中事先自帶的resource資源
例如:MediaPlayer.create(this, R.raw.test);
b. 存儲在SD卡或其他文件路徑下的媒體文件
例如:mp.setDataSource("/sdcard/test.mp3");
c. 網絡上的媒體文件
例如:mp.setDataSource("http://www.citynorth.cn/music/confucius.mp3");

MediaPlayer的setDataSource一共四個方法:
setDataSource (String path)
setDataSource (FileDescriptor fd)
setDataSource (Context context, Uri uri)
setDataSource (FileDescriptor fd, long offset, long length)
 
其中使用FileDescriptor時,需要將文件放到與res文件夾平級的assets文件夾裏,然後使用:
AssetFileDescriptor fileDescriptor = getAssets().openFd("rain.mp3");
m_mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),fileDescriptor.getStartOffset(), fileDescriptor.getLength());
來設置datasource

3)對播放器的主要控制方法:
Android通過控制播放器的狀態的方式來控制媒體文件的播放,其中:
prepare()和prepareAsync() 提供了同步和異步兩種方式設置播放器進入prepare狀態,需要注意的是,如果MediaPlayer實例是由create方法創建的,那麼第一次啓動播放前不需要再調用prepare()了,因爲create方法裏已經調用過了。
start()是真正啓動文件播放的方法,
pause()和stop()比較簡單,起到暫停和停止播放的作用,

seekTo()是定位方法,可以讓播放器從指定的位置開始播放,需要注意的是該方法是個異步方法,也就是說該方法返回時並不意味着定位完成,尤其是播放的網絡文件,真正定位完成時會觸發OnSeekComplete.onSeekComplete(),如果需要是可以調用setOnSeekCompleteListener(OnSeekCompleteListener)設置監聽器來處理的。
release()可以釋放播放器佔用的資源,一旦確定不再使用播放器時應當儘早調用它釋放資源。
reset()可以使播放器從Error狀態中恢復過來,重新會到Idle狀態。

4)設置播放器的監聽器:
MediaPlayer提供了一些設置不同監聽器的方法來更好地對播放器的工作狀態進行監聽,以期及時處理各種情況,
如:
setOnCompletionListener(MediaPlayer.OnCompletionListener listener)、
setOnErrorListener(MediaPlayer.OnErrorListener listener)
等,設置播放器時需要考慮到播放器可能出現的情況設置好監聽和處理邏輯,以保持播放器的健壯性。




下面是一個結合seekbar而簡易實現的在線播放和下載功能的音樂播放器demo



效果實現:


本篇博客是在多線程下載那篇博客增加在線播放音樂實現,下面是提供項目下載地址:

下面介紹具體實現過程:

定義一個具有緩衝效果的播放器:Player
我們看到的緩衝效果,是通過設置拖動條SeekBar的二級進度實現的,這就要設置MediaPlayer的緩衝更新的監聽了。
具體代碼實現:
[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. package com.wwj.download.util;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.Timer;  
  5. import java.util.TimerTask;  
  6.   
  7. import android.media.AudioManager;  
  8. import android.media.MediaPlayer;  
  9. import android.media.MediaPlayer.OnBufferingUpdateListener;  
  10. import android.media.MediaPlayer.OnCompletionListener;  
  11. import android.media.MediaPlayer.OnPreparedListener;  
  12. import android.os.Handler;  
  13. import android.util.Log;  
  14. import android.widget.SeekBar;  
  15.   
  16. public class Player implements OnBufferingUpdateListener, OnCompletionListener,  
  17.         OnPreparedListener {  
  18.   
  19.     public MediaPlayer mediaPlayer; // 媒體播放器  
  20.     private SeekBar seekBar; // 拖動條  
  21.     private Timer mTimer = new Timer(); // 計時器  
  22.   
  23.     // 初始化播放器  
  24.     public Player(SeekBar seekBar) {  
  25.         super();  
  26.         this.seekBar = seekBar;  
  27.         try {  
  28.             mediaPlayer = new MediaPlayer();  
  29.             mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);// 設置媒體流類型  
  30.             mediaPlayer.setOnBufferingUpdateListener(this);  
  31.             mediaPlayer.setOnPreparedListener(this);  
  32.         } catch (Exception e) {  
  33.             e.printStackTrace();  
  34.         }  
  35.         // 每一秒觸發一次  
  36.         mTimer.schedule(timerTask, 01000);  
  37.     }  
  38.   
  39.     // 計時器  
  40.     TimerTask timerTask = new TimerTask() {  
  41.   
  42.         @Override  
  43.         public void run() {  
  44.             if (mediaPlayer == null)  
  45.                 return;  
  46.             if (mediaPlayer.isPlaying() && seekBar.isPressed() == false) {  
  47.                 handler.sendEmptyMessage(0); // 發送消息  
  48.             }  
  49.         }  
  50.     };  
  51.   
  52.     Handler handler = new Handler() {  
  53.         public void handleMessage(android.os.Message msg) {  
  54.             int position = mediaPlayer.getCurrentPosition();  
  55.             int duration = mediaPlayer.getDuration();  
  56.             if (duration > 0) {  
  57.                 // 計算進度(獲取進度條最大刻度*當前音樂播放位置 / 當前音樂時長)  
  58.                 long pos = seekBar.getMax() * position / duration;  
  59.                 seekBar.setProgress((int) pos);  
  60.             }  
  61.         };  
  62.     };  
  63.   
  64.     public void play() {  
  65.         mediaPlayer.start();  
  66.     }  
  67.   
  68.     /** 
  69.      *  
  70.      * @param url 
  71.      *            url地址 
  72.      */  
  73.     public void playUrl(String url) {  
  74.         try {  
  75.             mediaPlayer.reset();  
  76.             mediaPlayer.setDataSource(url); // 設置數據源  
  77.             mediaPlayer.prepare(); // prepare自動播放  
  78.         } catch (IllegalArgumentException e) {  
  79.             e.printStackTrace();  
  80.         } catch (SecurityException e) {  
  81.             e.printStackTrace();  
  82.         } catch (IllegalStateException e) {  
  83.             e.printStackTrace();  
  84.         } catch (IOException e) {  
  85.             e.printStackTrace();  
  86.         }  
  87.     }  
  88.   
  89.     // 暫停  
  90.     public void pause() {  
  91.         mediaPlayer.pause();  
  92.     }  
  93.   
  94.     // 停止  
  95.     public void stop() {  
  96.         if (mediaPlayer != null) {  
  97.             mediaPlayer.stop();  
  98.             mediaPlayer.release();  
  99.             mediaPlayer = null;  
  100.         }  
  101.     }  
  102.   
  103.     // 播放準備  
  104.     @Override  
  105.     public void onPrepared(MediaPlayer mp) {  
  106.         mp.start();  
  107.         Log.e("mediaPlayer""onPrepared");  
  108.     }  
  109.   
  110.     // 播放完成  
  111.     @Override  
  112.     public void onCompletion(MediaPlayer mp) {  
  113.         Log.e("mediaPlayer""onCompletion");  
  114.     }  
  115.   
  116.     /** 
  117.      * 緩衝更新 
  118.      */  
  119.     @Override  
  120.     public void onBufferingUpdate(MediaPlayer mp, int percent) {  
  121.         seekBar.setSecondaryProgress(percent);  
  122.         int currentProgress = seekBar.getMax()  
  123.                 * mediaPlayer.getCurrentPosition() / mediaPlayer.getDuration();  
  124.         Log.e(currentProgress + "% play", percent + " buffer");  
  125.     }  
  126.   
  127. }  


[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. package com.wwj.download;  
  2.   
  3. import java.io.File;  
  4. import java.io.UnsupportedEncodingException;  
  5. import java.net.URLEncoder;  
  6.   
  7. import android.app.Activity;  
  8. import android.os.Bundle;  
  9. import android.os.Environment;  
  10. import android.os.Handler;  
  11. import android.os.Message;  
  12. import android.view.View;  
  13. import android.widget.Button;  
  14. import android.widget.EditText;  
  15. import android.widget.ProgressBar;  
  16. import android.widget.SeekBar;  
  17. import android.widget.SeekBar.OnSeekBarChangeListener;  
  18. import android.widget.TextView;  
  19. import android.widget.Toast;  
  20.   
  21. import com.wwj.download.util.Player;  
  22. import com.wwj.net.download.DownloadProgressListener;  
  23. import com.wwj.net.download.FileDownloader;  
  24.   
  25. public class MainActivity extends Activity {  
  26.     private static final int PROCESSING = 1;  
  27.     private static final int FAILURE = -1;  
  28.   
  29.     private EditText pathText; // url地址  
  30.     private TextView resultView;  
  31.     private Button downloadButton;  
  32.     private Button stopButton;  
  33.     private ProgressBar progressBar;  
  34.     private Button playBtn;  
  35.     private Player player; // 播放器  
  36.     private SeekBar musicProgress; // 音樂進度  
  37.   
  38.     private Handler handler = new UIHandler();  
  39.   
  40.     private final class UIHandler extends Handler {  
  41.         public void handleMessage(Message msg) {  
  42.             switch (msg.what) {  
  43.             case PROCESSING: // 更新進度  
  44.                 progressBar.setProgress(msg.getData().getInt("size"));  
  45.                 float num = (float) progressBar.getProgress()  
  46.                         / (float) progressBar.getMax();  
  47.                 int result = (int) (num * 100); // 計算進度  
  48.                 resultView.setText(result + "%");  
  49.                 if (progressBar.getProgress() == progressBar.getMax()) { // 下載完成  
  50.                     Toast.makeText(getApplicationContext(), R.string.success,  
  51.                             Toast.LENGTH_LONG).show();  
  52.                 }  
  53.                 break;  
  54.             case FAILURE: // 下載失敗  
  55.                 Toast.makeText(getApplicationContext(), R.string.error,  
  56.                         Toast.LENGTH_LONG).show();  
  57.                 break;  
  58.             }  
  59.         }  
  60.     }  
  61.   
  62.     @Override  
  63.     protected void onCreate(Bundle savedInstanceState) {  
  64.         super.onCreate(savedInstanceState);  
  65.         setContentView(R.layout.main);  
  66.         pathText = (EditText) findViewById(R.id.path);  
  67.         resultView = (TextView) findViewById(R.id.resultView);  
  68.         downloadButton = (Button) findViewById(R.id.downloadbutton);  
  69.         stopButton = (Button) findViewById(R.id.stopbutton);  
  70.         progressBar = (ProgressBar) findViewById(R.id.progressBar);  
  71.         ButtonClickListener listener = new ButtonClickListener();  
  72.         downloadButton.setOnClickListener(listener);  
  73.         stopButton.setOnClickListener(listener);  
  74.         playBtn = (Button) findViewById(R.id.btn_online_play);  
  75.         playBtn.setOnClickListener(listener);  
  76.         musicProgress = (SeekBar) findViewById(R.id.music_progress);  
  77.         player = new Player(musicProgress);  
  78.         musicProgress.setOnSeekBarChangeListener(new SeekBarChangeEvent());  
  79.     }  
  80.   
  81.     private final class ButtonClickListener implements View.OnClickListener {  
  82.         @Override  
  83.         public void onClick(View v) {  
  84.             switch (v.getId()) {  
  85.             case R.id.downloadbutton: // 開始下載  
  86.                 // http://abv.cn/music/光輝歲月.mp3,可以換成其他文件下載的鏈接  
  87.                 String path = pathText.getText().toString();  
  88.                 String filename = path.substring(path.lastIndexOf('/') + 1);  
  89.   
  90.                 try {  
  91.                     // URL編碼(這裏是爲了將中文進行URL編碼)  
  92.                     filename = URLEncoder.encode(filename, "UTF-8");  
  93.                 } catch (UnsupportedEncodingException e) {  
  94.                     e.printStackTrace();  
  95.                 }  
  96.   
  97.                 path = path.substring(0, path.lastIndexOf("/") + 1) + filename;  
  98.                 if (Environment.getExternalStorageState().equals(  
  99.                         Environment.MEDIA_MOUNTED)) {  
  100.                     // File savDir =  
  101.                     // Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);  
  102.                     // 保存路徑  
  103.                     File savDir = Environment.getExternalStorageDirectory();  
  104.                     download(path, savDir);  
  105.                 } else {  
  106.                     Toast.makeText(getApplicationContext(),  
  107.                             R.string.sdcarderror, Toast.LENGTH_LONG).show();  
  108.                 }  
  109.                 downloadButton.setEnabled(false);  
  110.                 stopButton.setEnabled(true);  
  111.                 break;  
  112.             case R.id.stopbutton: // 暫停下載  
  113.                 exit();  
  114.                 Toast.makeText(getApplicationContext(),  
  115.                         "Now thread is Stopping!!", Toast.LENGTH_LONG).show();  
  116.                 downloadButton.setEnabled(true);  
  117.                 stopButton.setEnabled(false);  
  118.                 break;  
  119.             case R.id.btn_online_play:  
  120.                 new Thread(new Runnable() {  
  121.   
  122.                     @Override  
  123.                     public void run() {  
  124.                         player.playUrl(pathText.getText().toString());  
  125.                     }  
  126.                 }).start();  
  127.                 break;  
  128.             }  
  129.         }  
  130.   
  131.         /* 
  132.          * 由於用戶的輸入事件(點擊button, 觸摸屏幕....)是由主線程負責處理的,如果主線程處於工作狀態, 
  133.          * 此時用戶產生的輸入事件如果沒能在5秒內得到處理,系統就會報“應用無響應”錯誤。 
  134.          * 所以在主線程裏不能執行一件比較耗時的工作,否則會因主線程阻塞而無法處理用戶的輸入事件, 
  135.          * 導致“應用無響應”錯誤的出現。耗時的工作應該在子線程裏執行。 
  136.          */  
  137.         private DownloadTask task;  
  138.   
  139.         private void exit() {  
  140.             if (task != null)  
  141.                 task.exit();  
  142.         }  
  143.   
  144.         private void download(String path, File savDir) {  
  145.             task = new DownloadTask(path, savDir);  
  146.             new Thread(task).start();  
  147.         }  
  148.   
  149.         /** 
  150.          *  
  151.          * UI控件畫面的重繪(更新)是由主線程負責處理的,如果在子線程中更新UI控件的值,更新後的值不會重繪到屏幕上 
  152.          * 一定要在主線程裏更新UI控件的值,這樣才能在屏幕上顯示出來,不能在子線程中更新UI控件的值 
  153.          *  
  154.          */  
  155.         private final class DownloadTask implements Runnable {  
  156.             private String path;  
  157.             private File saveDir;  
  158.             private FileDownloader loader;  
  159.   
  160.             public DownloadTask(String path, File saveDir) {  
  161.                 this.path = path;  
  162.                 this.saveDir = saveDir;  
  163.             }  
  164.   
  165.             /** 
  166.              * 退出下載 
  167.              */  
  168.             public void exit() {  
  169.                 if (loader != null)  
  170.                     loader.exit();  
  171.             }  
  172.   
  173.             DownloadProgressListener downloadProgressListener = new DownloadProgressListener() {  
  174.                 @Override  
  175.                 public void onDownloadSize(int size) {  
  176.                     Message msg = new Message();  
  177.                     msg.what = PROCESSING;  
  178.                     msg.getData().putInt("size", size);  
  179.                     handler.sendMessage(msg);  
  180.                 }  
  181.             };  
  182.   
  183.             public void run() {  
  184.                 try {  
  185.                     // 實例化一個文件下載器  
  186.                     loader = new FileDownloader(getApplicationContext(), path,  
  187.                             saveDir, 3);  
  188.                     // 設置進度條最大值  
  189.                     progressBar.setMax(loader.getFileSize());  
  190.                     loader.download(downloadProgressListener);  
  191.                 } catch (Exception e) {  
  192.                     e.printStackTrace();  
  193.                     handler.sendMessage(handler.obtainMessage(FAILURE)); // 發送一條空消息對象  
  194.                 }  
  195.             }  
  196.         }  
  197.     }  
  198.   
  199.     // 進度改變  
  200.     class SeekBarChangeEvent implements OnSeekBarChangeListener {  
  201.         int progress;  
  202.   
  203.         @Override  
  204.         public void onProgressChanged(SeekBar seekBar, int progress,  
  205.                 boolean fromUser) {  
  206.             // 原本是(progress/seekBar.getMax())*player.mediaPlayer.getDuration()  
  207.             this.progress = progress * player.mediaPlayer.getDuration()  
  208.                     / seekBar.getMax();  
  209.         }  
  210.   
  211.         @Override  
  212.         public void onStartTrackingTouch(SeekBar seekBar) {  
  213.   
  214.         }  
  215.   
  216.         @Override  
  217.         public void onStopTrackingTouch(SeekBar seekBar) {  
  218.             // seekTo()的參數是相對與影片時間的數字,而不是與seekBar.getMax()相對的數字  
  219.             player.mediaPlayer.seekTo(progress);  
  220.         }  
  221.   
  222.     }  
  223.   
  224.     @Override  
  225.     protected void onDestroy() {  
  226.         super.onDestroy();  
  227.         if (player != null) {  
  228.             player.stop();  
  229.             player = null;  
  230.         }  
  231.     }  
  232.   
  233. }  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章