Android MediaPlayer

MediaPlayer react

這個類主要是播放視頻類. android

AudioManager api

這個類管理在一個設備上的音頻資源和音頻輸出流. 網絡


Manifest聲明 app

1.網絡聲明 框架

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

2.若是播放器應用須要將屏幕變暗或者中止處理器,或者須要調用 MediaPlayer.setScreenOnWhilePlaying() 或者 MediaPlayer.setWakeMode()  方法,須要聲明: async

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


MediaPlayer類的使用 post

MediaPlayer類支持幾種不一樣媒體來源例如:

1. 本地資源

2. 網絡URI

3. 外部URL()


媒體來源1: 本地資源(存儲在應該的res/raw/ 目錄下)

MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1);
mediaPlayer.start(); // no need to call prepare(); create() does that for you

這種狀況下,一個"raw"資源是不須要系統作任何解析的一個文件.然而,這個資源不該該是原始音頻文件.它應該是一個被支持的正確編碼和格式化的媒體文件.


媒體來源2: 網絡URI

Uri myUri = ....; // initialize Uri here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(getApplicationContext(), myUri);
mediaPlayer.prepare();
mediaPlayer.start();


媒體來源3: 經過HTTP取得的遠程URL

String url = "http://........"; // your URL here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.start();

注意:在調用setDataSource(), 方法的時候必定要catch 得到 拋出  IllegalArgumentException  IOException 兩個異常,由於你定義的文件可能不存在.  


Asynchronous Preparation 異步準備

原則上能夠直接使用MediaPlayer.可是,有一些事情必需要一體化例如,調用prepare()  方法可能花費很長時間來執行,由於它可能涉及到抓取或者編碼媒體數據.所以,這中狀況下任何方法都有可能花費很長時間去執行,你不該該在UI線程中調用這個方法.

框架支持的一個很方便完成這個操做的方法是:調用 prepareAsync() 方法.這個方法在後臺開始prepare媒體而且立刻就返回.media準備完成.經過設置 setOnPreparedListener()  的 MediaPlayer.OnPreparedListener 接口中 onPrepared() 方法就會被調用.


Managing State(狀態管理)

 MediaPlayer 有一個內部狀態當你寫你的代碼時你必須時刻注意,由於某些操做只有在特定的狀態下才有效.

具體狀態請查看SDK文檔中 MediaPlayer 類.


Releasing the MediaPlayer(釋放MediaPlayer)

一個MediaPlayer 可能會消耗大量的系統資源.所以,你應該老是採起額外的方式去確保你不會持有一個MediaPlayer 實例,超過實際須要.

當你完成操做時時,你應該老是調用 release() 方法去確保任何分配的系統資源給正確的釋放掉.例如,當你使用一個MediaPlayer 而你的activity調用onStop()方法時,你必定要釋放MediaPlayer .由於當你的activity沒有和用戶交互的時候,去持有一個MediaPlayer意義不大.(除非須要在後臺播放媒體文件).

當你的activityresumed  或者 restarted 狀態,你須要去建立一個新的MediaPlayer  而且準備再次回覆以前的播放.

這裏是釋放和讓MediaPlayer 爲null的代碼:

mediaPlayer.release();
mediaPlayer = null;


Using a Service with MediaPlayer

Running asynchronously(異步運行)

首先,像一個activity同樣,在一個Service中的全部工做默認的是在一個單獨的線程中,若是你在同一個應用中運行一個activity和一個Service,默認的他們使用的是同一個線程(主線程).所以,service須要快速處理引入的intent而且在處理這些intent的時候不要處理冗長的運算.

若是須要這麼作,你必定要異步處理這些事情.

舉例來講,當在你的主線程中使用一個 MediaPlayer 時.你應該調用 prepareAsync()  而不是 prepare() ,例如:

public class MyService extends Service implements MediaPlayer.OnPreparedListener {
    private static final ACTION_PLAY = "com.example.action.PLAY";
    MediaPlayer mMediaPlayer = null;

    public int onStartCommand(Intent intent, int flags, int startId) {
        ...
        if (intent.getAction().equals(ACTION_PLAY)) {
            mMediaPlayer = ... // initialize it here
            mMediaPlayer.setOnPreparedListener(this);
            mMediaPlayer.prepareAsync(); // prepare async to not block main thread
        }
    }

    /** Called when MediaPlayer is ready */
    public void onPrepared(MediaPlayer player) {
        player.start();
    }
}



Handling asynchronous errors(異常異步處理)

public class MyService extends Service implements MediaPlayer.OnErrorListener {
    MediaPlayer mMediaPlayer;

    public void initMediaPlayer() {
        // ...initialize the MediaPlayer here...

        mMediaPlayer.setOnErrorListener(this);
    }

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        // ... react appropriately ...
        // The MediaPlayer has moved to the Error state, must be reset!
    }
}

這個是很重要的,當一個錯誤出現, MediaPlayer 移動到到Error狀態而且在你再次使用它以前你必定要重置 MediaPlayer.



Using wake locks

當設計應用在後臺播放媒體文件時,設備在你的service運行的時候可能會待機由於android系統在設備待機的時候嘗試節省電池.全部系統會嘗試切斷任何非必要的手機特徵,包括CPUWifi硬件.然而,若是你的service正在播放或者流處理音樂,你會想防止系統干擾你的播放.

爲了確保你的service繼續運行在這些條件下,你須要使用"wake locks".一個wake lock 是一種提醒體統你的應用正在使用一些特性,系統應該保持可用,就算電話處於空閒狀態.

注意:你應該老是節儉的使用wake locks,而且持有他們只有在真正必要的時候,由於他們會大大下降設備電池壽命.

要確保CPU在你的 MediaPlayer  播放的時候繼續處於運行狀態,當初始化你的 MediaPlayer 時調用 setWakeMode()  . 一旦你這麼作了, MediaPlayer 會持有指定的lock在播放的時候而且在paused或者stoped狀態時,會釋放掉這個lock.

mMediaPlayer = new MediaPlayer();
// ... other initialization here ...
mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);

在這個例子中得到wake lock 的前提是隻有當CPU處於清醒狀態.若是你是經過網絡流媒體而且使用的是wifi的話,你能夠也想要去持有一個 WifiLock  ,這種方式你必須收到獲取和釋放.所以,當你開始經過遠程URL準備 MediaPlayer  時,你應該建立和得到 Wi-Fi lock .例如:

WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
    .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");

wifiLock.acquire();

當你暫停或者中止媒體,或者你很長時間沒有用到網絡,你應該釋放這個lock:

wifiLock.release();



Handling audio focus(處理音頻的焦點)

儘管只有一個activity能夠運行在任什麼時候候,可是android 是一個多任務環境.這給使用音頻的應用產生了一個特別的挑戰,由於哪裏只有一個音頻輸入可是可能有幾個媒體service競爭使用.android2.2以前,沒有一個內置機制來解決這個問題.這可能在某些狀況下致使糟糕的用戶體驗.

當你的應用須要輸入音頻時,你應該老是請求音頻聚焦(audio focus).一旦它有了,它可使用自由的輸出聲音了,可是它應該老是保持對焦點的監聽.若是它被通知它已經失去了音頻焦點,它應該立刻殺掉這個音頻或者下降它到一個安靜的水平而且只有當它再次接受到focus時再從新播放.

要請求音頻聚焦,你必定要調用 AudioManager 的 requestAudioFocus() 方法,

AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
    AudioManager.AUDIOFOCUS_GAIN);

if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    // could not get audio focus.
}

 requestAudioFocus() 方法的第一個參數是一個 AudioManager.OnAudioFocusChangeListener ,當一個音頻焦點發生改變的時候他的 onAudioFocusChange() 方法會被調用.

所以你能夠在activity或者service中實現這個接口:

class MyService extends Service
                implements AudioManager.OnAudioFocusChangeListener {
    // ....
    public void onAudioFocusChange(int focusChange) {
        // Do something based on focus change...
    }
}

focusChange  參數告訴你音頻焦點發生了什麼樣的改變:

· AUDIOFOCUS_GAIN你獲得這個音頻的焦點

· AUDIOFOCUS_LOSS你可能長時間失去了這個音頻的焦點你必定要中止全部的音頻播放.由於你應該但願不要在後臺聚焦太長事件,這個是一個好地方去儘量的釋放掉你的資源.例如:你應該釋放掉MediaPlayer.

· AUDIOFOCUS_LOSS_TRANSIENT你暫時的失去了音頻的焦點,可是應該要立刻回到焦點上.你必定要中止掉全部的音頻的播放,可是你能持有你的資源由於你可能很快的再次得到聚焦.

· AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK你暫時的失去了音頻的焦點,可是你容許繼續用小音量播放音樂而不是徹底殺掉音頻.

使用代碼:

public void onAudioFocusChange(int focusChange) {
    switch (focusChange) {
        case AudioManager.AUDIOFOCUS_GAIN:
            // resume playback
            if (mMediaPlayer == null) initMediaPlayer();
            else if (!mMediaPlayer.isPlaying()) mMediaPlayer.start();
            mMediaPlayer.setVolume(1.0f, 1.0f);
            break;

        case AudioManager.AUDIOFOCUS_LOSS:
            // Lost focus for an unbounded amount of time: stop playback and release media player
            if (mMediaPlayer.isPlaying()) mMediaPlayer.stop();
            mMediaPlayer.release();
            mMediaPlayer = null;
            break;

        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
            // Lost focus for a short time, but we have to stop
            // playback. We don't release the media player because playback
            // is likely to resume
            if (mMediaPlayer.isPlaying()) mMediaPlayer.pause();
            break;

        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
            // Lost focus for a short time, but it's ok to keep playing
            // at an attenuated level
            if (mMediaPlayer.isPlaying()) mMediaPlayer.setVolume(0.1f, 0.1f);
            break;
    }
}

記住這些api只有在API 等級爲8(android 2.2)或者之上才能用.

Handling the AUDIO_BECOMING_NOISY Intent 

有可能會出現噪音的狀況,例如,用戶先用耳機聽音樂,而後把耳機給拔出來的這種狀況.

你能夠經過處理 ACTION_AUDIO_BECOMING_NOISY 意圖來確保在這種狀況下,你的應用中止播放音樂.

<receiver android:name=".MusicIntentReceiver">
   <intent-filter>
      <action android:name="android.media.AUDIO_BECOMING_NOISY" />
   </intent-filter>
</receiver>

public class MusicIntentReceiver implements android.content.BroadcastReceiver {
   @Override
   public void onReceive(Context ctx, Intent intent) {
      if (intent.getAction().equals(
                    android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
          // signal your service to stop playback
          // (via an Intent, for instance)
      }
   }
}



文章連接:http://blog.csdn.net/murongshusheng/article/details/7580689

相關文章
相關標籤/搜索