1. 程式人生 > >Android:MediaSession框架介紹

Android:MediaSession框架介紹

音樂播放器專案會貫穿安卓的四大元件。在專案中,大家一定會在服務中使用MediaPlayer去播放音樂,但是介面如何控制服務進行音樂的更換、改變播放進度,大家往往會使用傳送廣播的方式去通知服務,同時,服務可以傳送廣播通知介面播放進度的變化。

      這時候問題來了:

     1.你喜歡在廣播接受者中完成解析資料變為指令的程式碼嗎?

      2.你覺得用廣播高效嗎?

     當然,你可以通過binder做為服務的代理來進行通訊,但是對於服務和介面的同步則又略顯捉急。(如果做過音樂播放器的同學當然知道我在說些什麼)

     在安卓5中,谷歌推出了MediaSession框架專門解決媒體播放時介面和服務通訊問題。

     要理解MediaSession框架,分別看看Media和Session:首先Media是媒體的意思,也就是說這個框架用於音視訊媒體;而Session呢,翻譯成中文就是會話的意思。一個會話,肯定是涉及兩方或以上;在MediaSession框架中,有受控端(一個)和控制端(可以有多個)。接下來為了保證受控端和控制端不串號(想象一個遙控器可以遙控同一型號的多臺電視),就有了SessionToken的概念,相當於我們在連線藍芽裝置時的配對碼,這樣就保證了不串號。在MediaSession框架中,最重要的三個類的概念就這麼多,接下來我們一起看看如何使用MediSession框架。

先放一張框架示意圖:


      上圖你看了可能會丈二和尚摸不清頭腦,請耐心地看下面的內容,一會回來看,你會覺得更加清晰了。

      框架的主要類:

一、基本框架搭建

1. 在服務中通過new  MediaSession( Context, String)構造出MediaSession,其中字串可以傳入包名(或任意)

2. 在服務中呼叫mediaSession.getSessionToken獲得Token物件

3. 通過IBinder把Token傳遞給繫結服務的Activity

4. 在Activity中繫結服務,拿到Token物件,並呼叫MediaController(Context, MediaSession.Token)獲得MediaController物件

二、裝置上的音樂載入

以上就完成了MediaSession框架的搭建。接下來就開始使用這個框架了。接下來我們看看如何使用框架去完成音樂列表載入。

1、 服務中通過MediaStore內容提供者查詢裝置上的音樂得到Cursor物件

2、 遍歷Cursor把查詢的結果封裝到List集合中MediaMetadata可以看作是一個map集合,鍵是String(需要MediaMetadata上的常量),值是音樂名稱、歌手、時常等資訊

3、 把List轉化成ListQueueItem和MediaMetadata是什麼關係呢?QueueItem在構造的時候,需要MediaDescription,而MediaDescription可以通過MediaMetadata獲得。在構造QueueItem時,注意id不重複。

4、 服務中的MediaSession呼叫setQueue(List)方法,來告知整個框架的各方,目前有哪些音樂可以播放。

5、 介面上可以通過MediaController的getQueue方法獲得播放列表(List)。當然了因為服務對音樂列表的查詢封裝會需要一些時間,那也可以給呼叫mediaController.registerCallback(MediaController.Callback) 給mediaController註冊一個監聽,每當受控端呼叫了setQueue方法,所有的回撥的onQueueChanged(List)都會被呼叫

三、音樂的播放

1、在Activity中呼叫

MediaController的getTransportControls()獲得TransportControls物件

2、在播放按鈕的點選事件上,呼叫TransportControls的play方法,

3、為了接受到介面上的play指令,需要在服務端的MediaSession上呼叫setCallback(MediaSession.Callback)方法,並實現MediaSession.Callback的onPlay方法

4、在onPlay方法中,服務端可以從播放列表中選取一首音樂去播放,

5、這時候介面上並不知道音樂已經播放了,就需要服務去通知介面,開始播放音樂了,服務中需要呼叫MediaSession的setPlaybackState(PlaybackState) 去通知介面開始播放了,對於PlaybackState物件,需要用它的構造去Builder去構造,你可以簡單的只用setState(int state, long position, float playbackSpeed)方法,其中state是PlaybackState的常量、position就是當前播放位置(可以從MediaPlayer上去獲取),而playbackSpeed預設是1就好了

6、現在介面要想知道播放狀態發生變化了,可實現MediaController.Callback的onPlaybackStateChanged方法,判斷如果狀態是正在播放,則可以改變播放按鈕的狀態為暫停樣式。現在你可以再看一遍上面的步驟,然後對照示意圖。需要特別說明的是MediaSession框架只負責通訊,並不涉及任何業務邏輯,具體對MediaPlayer的方法呼叫、音樂載入、最重要的就是明白TransportControls方法和MediaSession.Callback回撥的對應關係

以及MediaSession的方法和MediaController.Callback的回撥方法

四、MediaSession的精妙之處

MediaSession框架中個人感覺最妙的部分就是播放進度的獲取了

如果在原來,可通過不斷地呼叫MediaPlayer的getPosition獲取播放進度,但如果專案的整體架構比較好的話,介面是拿不到MediaPlayer物件的。在MediaSession框架中,完全不需要去獲取播放進度,當然前提是播放狀態是準確的。

我們來看看PlaybackState.Builder的setState方法:

setState(int state, long position, float playbackSpeed)

setState(int state, long position, float playbackSpeed, long updateTime)

第二個的方法比第一個的多了一個引數叫更新時間,其實第一個方法會呼叫第二個方法,並指定更新時間為開機至今的時間(因為開機時間無法更改,系統時間可以改)。

在介面上上如何獲得當前播放進度呢:

計算公式如下

((獲取當前開機時間 – 上次更新狀態的時間)

* 播放速度 +

上次更新狀態時的播放進度)

程式碼如下

long currentPosition = ((SystemClock.elapsedRealtime() – playbackState.getLastPositionUpdateTime() ) * playbackState. getPlaybackSpeed() ) + playbackState.getPosition();

總結

MediaSession框架對於播放的各種需求都非常優雅地提供了實現,這些都等待你的發現,而且還提供了擴充套件的控制元件,可以自己完成一些自定義的請求。

。正常執行專案需要翻牆,因為這個應用的音樂資源是從youtube上載入的。在看程式碼的時候需要把無關程式碼快速跳過,把握主線。

現在有同學可能會問了,MediaSession框架只能在安卓

5系統上使用,但現在安卓5的市場佔有率還比較低,如何相容低版本呢?Google公司在support-v

4(

21以上

版本)中也提供了MediaSessionCompact(android.support.v4.media.session.MediaSessionCompat)相容包。具體API大同小異。