Android開發之Mediaplayer

來源:互聯網
上載者:User

Android開發之Mediaplayer

 Android提供了常見的音頻、視頻的編碼、解碼機制。藉助於多媒體類MediaPlayer的支援,開發人員可以很方便在在應用中播放音頻、視頻。本篇部落客要講解在Android平台下如何播放一個音頻檔案。

  本篇部落客要內容如下:

  • MediaPlayer
  • MediaPlayer的音頻源
  • 使用MediaPlayer播放音樂
  • MediaPlayer提示
  • Demo--一個簡單的MP3播放器

    MediaPlayer

      上面提到過,Android下對於音頻、視頻的支援均需要使用到MediaPlayer,它主要用來控制Android下播放檔案或流的類。MediaPlayer處於Android多媒體包下"android.media.MediaPlayer",僅有一個無參的建構函式,雖然僅為我們提供了一個無參的建構函式,為了方便我們初始化,還為我們提供了幾個靜態create()方法用於完成MediaPlayer初始化的工作。

    • static MediaPlayer create(Context context,int resid):通過音頻資源的Id來建立一個MediaPlayer執行個體。
    • static MediaPlayer create(Context context,Uri uri):通過一個音頻資源的Uri地址來建立一個MediaPlayer執行個體。

        MediaPlayer除了通過上面兩個create()方法在初始化的時候指定媒體資源,還可以通過MediaPlayer.setDataSource()方法為初始化後的MediaPlayer設定媒體資源,setDataSource()具有多個重載函數,適用於不同的媒體資源來源,以下講解幾個常用的,其他的可以查閱官方文檔。

      • void setDataSource(String path):通過一個媒體資源的地址指定MediaPlayer的資料來源,這裡的path可以是一個本地路徑,也可以是網路路徑。
      • void setDataSource(Context context,Uri uri):通過一個Uri指定MediaPlayer的資料來源,這裡的Uri可以是網路路徑或這一個內容提供者的Uri。
      • void setDataSource(FileDescriptor fd):通過一個FileDescriptor指定一個MediaPlayer的資料來源。

        MediaPlayer的音頻源

          通過上面介紹的初始化MediaPlayer的播放時媒體資料來源的方法可以看出,MediaPlayer支援的資料來源有:本地檔案、內部的Uri(內容提供者)、外部Uri。

          如,設定一個本地SD卡的資源:

        1                 mediaPlayer = new MediaPlayer();2                 mediaPlayer.setDataSource("/sdcarc/a.mp3");

          注意讀記憶卡,還需要設定訪問記憶卡的許可權:

            

          如,設定一個外部uri的網路流媒體資源:

        1                 mediaPlayer = new MediaPlayer();2                 mediaPlayer.setDataSource(http://192.168.1.102:1231/music/a.mp3);

          如果訪問網路流媒體資源,還需要設定訪問網路的許可權:

            

        使用MediaPlayer播放音樂

          MediaPlayer其實是一個封裝的很好的音頻、視頻流媒體操作類,如果查看其源碼,會發現其內部是調用的native方法,所以它其實是有C++實現的。

          既然是一個流媒體操作類,那麼必然涉及到,播放、暫停、停止等操作,實際上MediaPlayer也為我們提供了相應的方法來直接操作流媒體。

        • void start():開始或恢複播放。
        • void stop():停止播放。
        • void pause():暫停播放。  

            通過上面三個方法,只要設定好流媒體資料來源,即可在應用中播放流媒體資源,為了更好的操作流媒體,MediaPlayer還為我們提供了一些其他的方法,這裡列出一些常用的,詳細內容參閱官方文檔。

          • int getDuration():擷取流媒體的總播放時間長度,單位是毫秒。
          • int getCurrentPosition():擷取當前流媒體的播放的位置,單位是毫秒。
          • void seekTo(int msec):設定當前MediaPlayer的播放位置,單位是毫秒。
          • void setLooping(boolean looping):設定是否迴圈播放。
          • boolean isLooping():判斷是否迴圈播放。
          • boolean isPlaying():判斷是否現正播放。
          • void prepare():同步的方式裝載流媒體檔案。
          • void prepareAsync():非同步方式裝載流媒體檔案。
          • void release ():回收流媒體資源。
          • void setAudioStreamType(int streamtype):設定播放流媒體類型。
          • void setWakeMode(Context context, int mode):設定CPU喚醒的狀態。
          • setNextMediaPlayer(MediaPlayer next):設定當前流媒體播放完畢,下一個播放的MediaPlayer。

              大部分方法的看方法名就可以理解,但是有幾個方法需要單獨說明一下。

              在使用MediaPlayer播放一段流媒體的時候,需要使用prepare()或prepareAsync()方法把流媒體裝載進MediaPlayer,才可以調用start()方法播放流媒體。                 

              setAudioStreamType()方法用於指定播放流媒體的類型,它傳遞的是一個int類型的資料,均以常量定義在AudioManager類中, 一般我們播放音頻檔案,設定為AudioManager.STREAM_MUSIC即可。

              

              除了上面介紹的一些方法外,MediaPlayer還提供了一些事件的回呼函數,這裡介紹幾個常用的:

            • setOnCompletionListener(MediaPlayer.OnCompletionListener listener):當流媒體播放完畢的時候回調。
            • setOnErrorListener(MediaPlayer.OnErrorListener listener):當播放中發生錯誤的時候回調。
            • setOnPreparedListener(MediaPlayer.OnPreparedListener listener):當裝載流媒體完畢的時候回調。
            • setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener):當使用seekTo()設定播放位置的時候回調。

              MediaPlayer提示

                在使用MediaPlayer的使用過程中,有個小技巧需要說明一下:

                1、在使用start()播放流媒體之前,需要裝載流媒體資源。這裡最好使用prepareAsync()用非同步方式裝載流媒體資源。因為流媒體資源的裝載是會消耗系統資源的,在一些硬體不理想的裝置上,如果使用prepare()同步的方式裝載資源,可能會造成UI介面的卡頓,這是非常影響用於體驗的。因為推薦使用非同步裝載的方式,為了避免還沒有裝載完成就調用start()而報錯的問題,需要綁定MediaPlayer.setOnPreparedListener()事件,它將在非同步裝載完成之後回調。非同步裝載還有一個好處就是避免裝載逾時引發ANR((Application Not Responding)錯誤。

               1                 mediaPlayer = new MediaPlayer(); 2                 mediaPlayer.setDataSource(path); 3                 mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 4                  5                 // 通過非同步方式裝載媒體資源 6                 mediaPlayer.prepareAsync(); 7                 mediaPlayer.setOnPreparedListener(new OnPreparedListener() {                     8                     @Override 9                     public void onPrepared(MediaPlayer mp) {10                         // 裝載完畢回調11                         mediaPlayer.start();12                     }13                 });                

                2、使用完MediaPlayer需要回收資源。MediaPlayer是很消耗系統資源的,所以在使用完MediaPlayer,不要等待系統自動回收,最好是主動回收資源。

              1         if (mediaPlayer != null && mediaPlayer.isPlaying()) {2             mediaPlayer.stop();3             mediaPlayer.release();4             mediaPlayer = null;5         }

                3、使用MediaPlayer最好使用一個Service來使用,並且在Service的onDestory()方法中回收MediaPlayer資源,實際上,就算是直接使用Activity承載MediaPlayer,也最好在銷毀的時候判斷一下MediaPlayer是否被回收,如果未被回收,回收其資源,因為底層調用的native方法,如果不銷毀還是會在底層繼續播放,而承載的組件已經被銷毀了,這個時候就無法擷取到這個MediaPlayer進而控制它。

              1     @Override2     protected void onDestroy() {3         if (mediaPlayer != null && mediaPlayer.isPlaying()) {4             mediaPlayer.stop();5             mediaPlayer.release();6             mediaPlayer = null;7         }8         super.onDestroy();9     }

                4、對於單曲迴圈之類的操作,除了可以使用setLooping()方法進行設定之外,還可以為MediaPlayer註冊回呼函數,MediaPlayer.setOnCompletionListener(),它會在MediaPlayer播放完畢被回調。

               1                 // 設定迴圈播放 2 //                mediaPlayer.setLooping(true); 3                 mediaPlayer.setOnCompletionListener(new OnCompletionListener() { 4                      5                     @Override 6                     public void onCompletion(MediaPlayer mp) { 7                         // 在播放完畢被回調 8                         play();                         9                     }10                 });

                5、因為MediaPlayer一直操作的是一個流媒體,所以無可避免的可能一段流媒體資源,前半段可以正常播放,而中間一段因為解析或者源檔案錯誤等問題,造成中間一段無法播放問題,需要我們處理這個錯誤,否則會影響Ux(使用者體驗)。可以為MediaPlayer註冊回呼函數setOnErrorListener()來設定出錯之後的解決辦法,一般重新播放或者播放下一個流媒體即可。  

              1                 mediaPlayer.setOnErrorListener(new OnErrorListener() {2                     3                     @Override4                     public boolean onError(MediaPlayer mp, int what, int extra) {5                         play();6                         return false;7                     }8                 });

              Demo--一個簡單的MP3播放器

                上面已經介紹了MediaPlayer播放一段音頻檔案的所有需要用到的內容。下面通過一個簡單的Demo來示範如何使用MediaPlayer播放一個SD卡上的MP3檔案。操作MediaPlayer應該放在Service中完成,這裡為了簡單,使用Activity直接操作MediaPlayer。代碼注釋裡寫的很清楚裡,這裡不再累述。

                執行這個樣本需要在/sdcard/目錄下存在xm.mp3的檔案。  

                1 package cn.bgxt.mediaplayerdemo;  2   3 import java.io.File;  4 import android.media.AudioManager;  5 import android.media.MediaPlayer;  6 import android.media.MediaPlayer.OnCompletionListener;  7 import android.media.MediaPlayer.OnErrorListener;  8 import android.media.MediaPlayer.OnPreparedListener;  9 import android.os.Bundle; 10 import android.app.Activity; 11 import android.view.View; 12 import android.widget.Button; 13 import android.widget.EditText; 14 import android.widget.Toast; 15  16 public class MainActivity extends Activity { 17     private EditText et_path; 18     private Button btn_play, btn_pause, btn_replay, btn_stop; 19     private MediaPlayer mediaPlayer; 20  21     @Override 22     protected void onCreate(Bundle savedInstanceState) { 23         super.onCreate(savedInstanceState); 24         setContentView(R.layout.activity_main); 25  26         et_path = (EditText) findViewById(R.id.et_path); 27         btn_play = (Button) findViewById(R.id.btn_play); 28         btn_pause = (Button) findViewById(R.id.btn_pause); 29         btn_replay = (Button) findViewById(R.id.btn_replay); 30         btn_stop = (Button) findViewById(R.id.btn_stop); 31  32         btn_play.setOnClickListener(click); 33         btn_pause.setOnClickListener(click); 34         btn_replay.setOnClickListener(click); 35         btn_stop.setOnClickListener(click); 36     } 37  38     private View.OnClickListener click = new View.OnClickListener() { 39  40         @Override 41         public void onClick(View v) { 42  43             switch (v.getId()) { 44             case R.id.btn_play: 45                 play(); 46                 break; 47             case R.id.btn_pause: 48                 pause(); 49                 break; 50             case R.id.btn_replay: 51                 replay(); 52                 break; 53             case R.id.btn_stop: 54                 stop(); 55                 break; 56             default: 57                 break; 58             } 59         } 60     }; 61     /** 62      * 播放音樂 63      */ 64     protected void play() { 65         String path = et_path.getText().toString().trim(); 66         File file = new File(path); 67         if (file.exists() && file.length() > 0) { 68             try { 69                 mediaPlayer = new MediaPlayer(); 70                 // 設定指定的流媒體地址 71                 mediaPlayer.setDataSource(path); 72                 // 設定音頻流的類型 73                 mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 74  75                 // 通過非同步方式裝載媒體資源 76                 mediaPlayer.prepareAsync(); 77                 mediaPlayer.setOnPreparedListener(new OnPreparedListener() { 78                     @Override 79                     public void onPrepared(MediaPlayer mp) { 80                         // 裝載完畢 開始播放流媒體 81                         mediaPlayer.start(); 82                         Toast.makeText(MainActivity.this, "開始播放", 0).show(); 83                         // 避免重複播放,把播放按鈕設定為不可用 84                         btn_play.setEnabled(false); 85                     } 86                 }); 87                 // 設定迴圈播放 88                 // mediaPlayer.setLooping(true); 89                 mediaPlayer.setOnCompletionListener(new OnCompletionListener() { 90  91                     @Override 92                     public void onCompletion(MediaPlayer mp) { 93                         // 在播放完畢被回調 94                         btn_play.setEnabled(true); 95                     } 96                 }); 97  98                 mediaPlayer.setOnErrorListener(new OnErrorListener() { 99 100                     @Override101                     public boolean onError(MediaPlayer mp, int what, int extra) {102                         // 如果發生錯誤,重新播放103                         replay();104                         return false;105                     }106                 });107             } catch (Exception e) {108                 e.printStackTrace();109                 Toast.makeText(this, "播放失敗", 0).show();110             }111         } else {112             Toast.makeText(this, "檔案不存在", 0).show();113         }114 115     }116     /**117      * 暫停118      */119     protected void pause() {120         if (btn_pause.getText().toString().trim().equals("繼續")) {121             btn_pause.setText("暫停");122             mediaPlayer.start();123             Toast.makeText(this, "繼續播放", 0).show();124             return;125         }126         if (mediaPlayer != null && mediaPlayer.isPlaying()) {127             mediaPlayer.pause();128             btn_pause.setText("繼續");129             Toast.makeText(this, "暫停播放", 0).show();130         }131 132     }133     134     /**135      * 重新播放136      */137     protected void replay() {138         if (mediaPlayer != null && mediaPlayer.isPlaying()) {139             mediaPlayer.seekTo(0);140             Toast.makeText(this, "重新播放", 0).show();141             btn_pause.setText("暫停");142             return;143         }        144         play();145     }146     147     /**148      * 停止播放149      */150     protected void stop() {151         if (mediaPlayer != null && mediaPlayer.isPlaying()) {152             mediaPlayer.stop();153             mediaPlayer.release();154             mediaPlayer = null;155             btn_play.setEnabled(true);156             Toast.makeText(this, "停止播放", 0).show();157         }158 159     }160 161     @Override162     protected void onDestroy() {163         // 在activity結束的時候回收資源164         if (mediaPlayer != null && mediaPlayer.isPlaying()) {165             mediaPlayer.stop();166             mediaPlayer.release();167             mediaPlayer = null;168         }169         super.onDestroy();170     }171 }

               效果展示:




相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.