1. 程式人生 > >深入Android MediaPlayer的使用方法詳解

深入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

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卡的資源:

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

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

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>

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

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

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

<uses-permission android:name="android.permission.INTERNET"></uses-permission

使用MediaPlayer播放音樂

  MediaPlayer其實是一個封裝的很好的音訊、視訊流媒體操作類,如果檢視其原始碼,會發現其內部是呼叫的native方法,所以它其實是有C++實現的。

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

  • void statr():開始或恢復播放。
  • 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)錯誤。

mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(path);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
// 通過非同步的方式裝載媒體資源
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
    @Override
public void onPrepared(MediaPlayer mp) {
        // 裝載完畢回撥
mediaPlayer.start();
}
});

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

if (mediaPlayer != null && mediaPlayer.isPlaying()) {
    mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}

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

@Override
protected void onDestroy() {
    if (mediaPlayer != null && mediaPlayer.isPlaying()) {
        mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
    super.onDestroy();
}

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

// 設定迴圈播放
// mediaPlayer.setLooping(true);
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {

    @Override
public void onCompletion(MediaPlayer mp) {
        // 在播放完畢被回撥
play();
}
});
 

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

mediaPlayer.setOnErrorListener(new OnErrorListener() {

    @Override
public boolean onError(MediaPlayer mp, int what, int extra) {
        play();
        return false;
}
});

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

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

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

public class MainActivity extends Activity {
    private EditText et_path;
    private Button btn_play, btn_pause, btn_replay, btn_stop;
    private MediaPlayer mediaPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_path = (EditText) findViewById(R.id.et_path);
btn_play = (Button) findViewById(R.id.btn_play);
btn_pause = (Button) findViewById(R.id.btn_pause);
btn_replay = (Button) findViewById(R.id.btn_replay);
btn_stop = (Button) findViewById(R.id.btn_stop);
btn_play.setOnClickListener(click);
btn_pause.setOnClickListener(click);
btn_replay.setOnClickListener(click);
btn_stop.setOnClickListener(click);
}

    private View.OnClickListener click = new View.OnClickListener() {
        @Override
public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn_play:
                    play();
                    break;
                case R.id.btn_pause:
                    pause();
                    break;
                case R.id.btn_replay:
                    replay();
                    break;
                case R.id.btn_stop:
                    stop();
                    break;
                default:
                    break;
}

        }

    };
/**
     * 播放音樂
     */
protected void play() {
        String path = et_path.getText().toString().trim();
File file = new File(path);
        if (file.exists() && file.length() != 0) {
            try {
                mediaPlayer = new MediaPlayer();
// 設定指定的流媒體地址
mediaPlayer.setDataSource(path);
// 設定音訊流的型別
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
// 通過非同步的方式裝載媒體資源
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
                    @Override
public void onPrepared(MediaPlayer mp) {
                        // 裝載完畢 開始播放流媒體
mediaPlayer.start();
Toast.makeText(MainActivity.this, "開始播放", 0).show();
// 避免重複播放,把播放按鈕設定為不可用
btn_play.setEnabled(false);
}

                });
// 設定迴圈播放
                // mediaPlayer.setLooping(true);
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {

                    @Override
public void onCompletion(MediaPlayer mp) {
                        // 在播放完畢被回撥
btn_play.setEnabled(true);
}

                });
mediaPlayer.setOnErrorListener(new OnErrorListener() {

                    @Override
public boolean onError(MediaPlayer mp, int what, int extra) {
                        // 如果發生錯誤,重新播放
replay();
                        return false;
}

                });
} catch (Exception e) {
                e.printStackTrace();
Toast.makeText(this, "播放失敗", 0).show();
}

        } else {
            Toast.makeText(this, "檔案不存在", 0).show();
}

    }

    /**
     * 暫停
     */
protected void pause() {
        if (btn_pause.getText().toString().trim().equals("繼續")) {
            btn_pause.setText("暫停");
mediaPlayer.start();
Toast.makeText(this, "繼續播放", 0).show();
            return;
}
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
btn_pause.setText("繼續");
Toast.makeText(this, "暫停播放", 0).show();
}

    }

    /**
     * 重新播放
     */
protected void replay() {
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.seekTo(0);
Toast.makeText(this, "重新播放", 0).show();
btn_pause.setText("暫停");
            return;
}
        play();
}

    /**
     * 停止播放
     */
protected void stop() {
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
btn_play.setEnabled(true);
Toast.makeText(this, "停止播放", 0).show();
}

    }


    @Override
protected void onDestroy() {
        // 在activity結束的時候回收資源
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
        super.onDestroy();
}

}

轉自文章   http://www.jb51.NET/article/38722.htm