MediaPlayer播放背景音樂(一)

本章目錄

  • Part One:播放器狀態
  • Part Two:播放背景音樂

一般來說,我們播放音樂使用的是MediaPlayer類,播放音效使用的是SoundPool。而說到MediaPlayer,就必然會出現下面這個圖:


MediaPlayer生命周期.gif

該圖描繪了MediaPlayer的各種狀態,也列出了主要方法的調用順序。需要注意的是,每個方法的應用需要特定的狀態,如果不正確調用,會拋出IllegalStateException異常。

Part One:播放器狀態

Idle狀態:當使用new方法創建一個MediaPlayer對象且調用reset()方法,MediaPlayer對象會處于Idle狀態。如果在該狀態先使用(getCurrentPosition(), getDuration(), getVideoHeight(), getVideoWidth(), setAudioStreamType(int), setLooping(boolean), setVolume(float, float), pause(), start(), stop(), seekTo(int), prepare() or prepareAsync())等方法(相當于在不對的時機調用),然后通過reset()方法進入Idle狀態會觸發OnErrorListener.onError(),同時MediaPlayer會進入Error狀態。如果是一個新創建的MediaPlayer對象,是不會觸發OnErrorListener.onError(),也就是說不會進入Error狀態。
End狀態:通過release()方法會進入End狀態,同時MediaPlayer對象將不再使用。如果無需使用MediaPlayer,應該立即通過release()方法釋放資源。如果MediaPlayer對象進入End狀態,就不會進入其它狀態了。
Initialized狀態:這個狀態相對來說比較簡單,MediaPlayer調用setDataSource ()會進入此狀態,相當于已經配置好將要播放的資源了。
Prepared狀態:當初始化完畢后,通過調用prepare()(同步的)或者prepareAsync()(異步的)方法,會處于Prepared狀態。它標示著當前MediaPlayer沒有錯誤,音樂可以播放了。
Preparing狀態:Preparing狀態很好理解,如果調用prepareAsync ()方法,當異步準備完畢后,會觸發OnPreparedListener.onPrepared (),從而進入Prepared狀態。也就是數,prepareAsync()方法會比prepare()方法多這么一個狀態。
Started狀態:很顯然,一旦MediaPlayer準備完畢,就可以調用start()方法,從而MediaPlayer進入Started狀態。這也標志著MediaPlayer進入到播放音樂階段,可以用isPlaying()方法測試是否在此狀態。如果播放完畢,同時設置loop循環,那么MediaPlayer會繼續待在Started狀態。同理,如果MediaPlayer調用seekTo()或者start()方法,可以使MediaPlayer保留在此狀態。
Paused狀態:當MediaPlayer處于Started狀態時,調用pause()方法會中止,并進入Paused狀態。調用start()方法會讓一個處于Paused狀態的MediaPlayer對象從之前暫停的地方恢復播放。Paused狀態可以調用seekTo()方法,對一個已經處于Paused狀態的MediaPlayer對象pause()方法沒有影響。
Stop狀態:Started狀態或者Paused狀態的MediaPalyer可以通過stop()方法停止。如果要恢復播放,需要通過prepareAsync()或者prepare()方法恢復到先前的狀態。
PlaybackCompleted狀態:如果文件正常播放完畢,并且沒有設置循環loop會進入此狀態,同時會觸發OnCompletionListener的onCompletion()方法。在這個狀態下,可以調用start()方法播放音樂,或者stop()停止,或者seekTo()重新定位要播放的音樂。
Error狀態:如果因為某些原因,MediaPlayer發生了錯誤,會觸發OnErrorListener.onError()事件,同時進入Error狀態。及時捕捉并妥善處理這些錯誤是很重要的,可以幫助我們及時釋放相關的軟硬件資源,也可以改善用戶體驗。如果MediaPlayer進入Error狀態,通過reset()方法可以恢復到Idle狀態。

Part Two:播放背景音樂

相對于一款音樂播放器的邏輯來說,播放背景音樂的實現十分的簡單。至于更深層次的功能擴展, 比如音樂播放器,錄音等,也只是在現有的結構上多添加一些方法而已,就不再贅述了,有興趣的可以自行研究。

  1. 要播放背景音樂,首先要將MP3文件導入到項目的assets資產目錄中。
    assets目錄下的文件在打包后會原封不動的保存在apk包中,不會被編譯成二進制。一般拷貝數據庫到sdcard,游戲數據或者Hybrid開發等需要用到此目錄,我們的音頻文件不想被編譯,所以也要放到這里。
    操作步驟為:
  • 鼠標右鍵選中項目,依次點擊 new -> Folder -> Assets Folder ->finish,即可完成目錄創建。
  • 將事先準備好的MP3文件拷貝到該目錄,注意不要超過50MB。
  1. 通過AssetManager獲取到音樂文件。
    代碼比較簡單,就是獲取AssetManager對象,然后通過文件名獲得FileDescriptor對象:
    @Nullable
    private AssetFileDescriptor getAssetFileDescriptor() {
        AssetManager assetManager = getAssets();
        AssetFileDescriptor fileDescriptor = null;
        try {
             fileDescriptor = assetManager.openFd("Westlife - Beautiful in white.mp3");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return fileDescriptor;
    }
  1. 播放背景音樂
    播放背景音樂的邏輯可參考之前說的MediaPlayer狀態圖,依次調用相應的方法,走完Idle - > Initialized -> Preparing -> Prepared - > Started這幾個狀態即可。
    之所以使用prepareAsync()方法是為了異步加載資源,避免資源過大,阻礙主線程。
private void playBGM(AssetFileDescriptor fileDescriptor) {
        mediaPlayer = new MediaPlayer();
        try {
            mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(), fileDescriptor.getStartOffset(), fileDescriptor.getLength());
            mediaPlayer.setLooping(true);
            mediaPlayer.prepareAsync();
            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    mediaPlayer.start();
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

背景音樂的初步需求已經實現了,但是使用上還有很大的局限性,要想完善它,需要引入Service和BroadcastReceiver這倆個組件,下一節再細說。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,698評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,202評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,742評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,580評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,297評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,688評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,693評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,875評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,438評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,183評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,384評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,931評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,612評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,022評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,297評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,093評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,330評論 2 377

推薦閱讀更多精彩內容