您好,登錄后才能下訂單哦!
很多同學(xué),在學(xué)習(xí)安卓的時(shí)候,可能會(huì)完成一個(gè)音樂播放器的項(xiàng)目,因?yàn)橐魳凡シ牌黜?xiàng)目會(huì)貫穿安卓的四大組件。在項(xiàng)目中,大家一定會(huì)在服務(wù)中使用MediaPlayer去播放音樂,但是界面如何控制服務(wù)進(jìn)行音樂的更換、改變播放進(jìn)度,大家往往會(huì)使用發(fā)送廣播的方式去通知服務(wù),同時(shí),服務(wù)可以發(fā)送廣播通知界面播放進(jìn)度的變化。
這時(shí)候問題來了:
1.你喜歡在廣播接受者中完成解析數(shù)據(jù)變?yōu)橹噶畹拇a嗎?
2.你覺得用廣播高效嗎?
當(dāng)然,你可以通過binder做為服務(wù)的代理來進(jìn)行通訊,但是對于服務(wù)和界面的同步則又略顯捉急。(如果做過音樂播放器的同學(xué)當(dāng)然知道我在說些什么)
在安卓5中,谷歌推出了MediaSession框架專門解決媒體播放時(shí)界面和服務(wù)通訊問題。
要理解MediaSession框架,分別看看Media和Session:首先Media是媒體的意思,也就是說這個(gè)框架用于音視頻媒體;而Session呢,翻譯成中文就是會(huì)話的意思。一個(gè)會(huì)話,肯定是涉及兩方或以上;在MediaSession框架中,有受控端(一個(gè))和控制端(可以有多個(gè))。接下來為了保證受控端和控制端不串號(想象一個(gè)遙控器可以遙控同一型號的多臺(tái)電視),就有了SessionToken的概念,相當(dāng)于我們在連接藍(lán)牙設(shè)備時(shí)的配對碼,這樣就保證了不串號。在MediaSession框架中,最重要的三個(gè)類的概念就這么多,接下來我們一起看看如何使用MediSession框架。
先放一張框架示意圖:
上圖你看了可能會(huì)丈二和尚摸不清頭腦,請耐心地看下面的內(nèi)容,一會(huì)回來看,你會(huì)覺得更加清晰了。
框架的主要類:
一、基本框架搭建
1. 在服務(wù)中通過new MediaSession( Context, String)構(gòu)造出MediaSession,其中字符串可以傳入包名(或任意)
2. 在服務(wù)中調(diào)用mediaSession.getSessionToken獲得Token對象
3. 通過IBinder把Token傳遞給綁定服務(wù)的Activity
4. 在Activity中綁定服務(wù),拿到Token對象,并調(diào)用MediaController(Context, MediaSession.Token)獲得MediaController對象
二、設(shè)備上的音樂加載
以上就完成了MediaSession框架的搭建。接下來就開始使用這個(gè)框架了。接下來我們看看如何使用框架去完成音樂列表加載。
1、 服務(wù)中通過MediaStore內(nèi)容提供者查詢設(shè)備上的音樂得到Cursor對象
2、 遍歷Cursor把查詢的結(jié)果封裝到List集合中MediaMetadata可以看作是一個(gè)map集合,鍵是String(需要MediaMetadata上的常量),值是音樂名稱、歌手、時(shí)常等信息
3、 把List轉(zhuǎn)化成ListQueueItem和MediaMetadata是什么關(guān)系呢?QueueItem在構(gòu)造的時(shí)候,需要MediaDescription,而MediaDescription可以通過MediaMetadata獲得。在構(gòu)造QueueItem時(shí),注意id不重復(fù)。
4、 服務(wù)中的MediaSession調(diào)用setQueue(List)方法,來告知整個(gè)框架的各方,目前有哪些音樂可以播放。
5、 界面上可以通過MediaController的getQueue方法獲得播放列表(List)。當(dāng)然了因?yàn)榉?wù)對音樂列表的查詢封裝會(huì)需要一些時(shí)間,那也可以給調(diào)用mediaController.registerCallback(MediaController.Callback) 給mediaController注冊一個(gè)監(jiān)聽,每當(dāng)受控端調(diào)用了setQueue方法,所有的回調(diào)的onQueueChanged(List)都會(huì)被調(diào)用
三、音樂的播放
1、在Activity中調(diào)用
MediaController的getTransportControls()獲得TransportControls對象
2、在播放按鈕的點(diǎn)擊事件上,調(diào)用TransportControls的play方法,
3、為了接受到界面上的play指令,需要在服務(wù)端的MediaSession上調(diào)用setCallback(MediaSession.Callback)方法,并實(shí)現(xiàn)MediaSession.Callback的onPlay方法
4、在onPlay方法中,服務(wù)端可以從播放列表中選取一首音樂去播放,
5、這時(shí)候界面上并不知道音樂已經(jīng)播放了,就需要服務(wù)去通知界面,開始播放音樂了,服務(wù)中需要調(diào)用MediaSession的setPlaybackState(PlaybackState) 去通知界面開始播放了,對于PlaybackState對象,需要用它的構(gòu)造去Builder去構(gòu)造,你可以簡單的只用setState(int state, long position, float playbackSpeed)方法,其中state是PlaybackState的常量、position就是當(dāng)前播放位置(可以從MediaPlayer上去獲取),而playbackSpeed默認(rèn)是1就好了
6、現(xiàn)在界面要想知道播放狀態(tài)發(fā)生變化了,可實(shí)現(xiàn)MediaController.Callback的onPlaybackStateChanged方法,判斷如果狀態(tài)是正在播放,則可以改變播放按鈕的狀態(tài)為暫停樣式。現(xiàn)在你可以再看一遍上面的步驟,然后對照示意圖。需要特別說明的是MediaSession框架只負(fù)責(zé)通訊,并不涉及任何業(yè)務(wù)邏輯,具體對MediaPlayer的方法調(diào)用、音樂加載、最重要的就是明白TransportControls方法和MediaSession.Callback回調(diào)的對應(yīng)關(guān)系
以及MediaSession的方法和MediaController.Callback的回調(diào)方法
四、MediaSession的精妙之處
MediaSession框架中個(gè)人感覺最妙的部分就是播放進(jìn)度的獲取了
如果在原來,可通過不斷地調(diào)用MediaPlayer的getPosition獲取播放進(jìn)度,但如果項(xiàng)目的整體架構(gòu)比較好的話,界面是拿不到MediaPlayer對象的。在MediaSession框架中,完全不需要去獲取播放進(jìn)度,當(dāng)然前提是播放狀態(tài)是準(zhǔn)確的。
我們來看看PlaybackState.Builder的setState方法:
setState(int state, long position, float playbackSpeed)
setState(int state, long position, float playbackSpeed, long updateTime)
第二個(gè)的方法比第一個(gè)的多了一個(gè)參數(shù)叫更新時(shí)間,其實(shí)第一個(gè)方法會(huì)調(diào)用第二個(gè)方法,并指定更新時(shí)間為開機(jī)至今的時(shí)間(因?yàn)殚_機(jī)時(shí)間無法更改,系統(tǒng)時(shí)間可以改)。
在界面上上如何獲得當(dāng)前播放進(jìn)度呢:
計(jì)算公式如下
((獲取當(dāng)前開機(jī)時(shí)間 – 上次更新狀態(tài)的時(shí)間)
* 播放速度 +
上次更新狀態(tài)時(shí)的播放進(jìn)度)
代碼如下
long currentPosition = ((SystemClock.elapsedRealtime() – playbackState.getLastPositionUpdateTime() ) * playbackState. getPlaybackSpeed() ) + playbackState.getPosition();
總結(jié)
MediaSession框架對于播放的各種需求都非常優(yōu)雅地提供了實(shí)現(xiàn),這些都等待你的發(fā)現(xiàn),而且還提供了擴(kuò)展的控件,可以自己完成一些自定義的請求。
具體的代碼,可以參照谷歌官方的項(xiàng)目:https://github.com/googlesamples/android-UniversalMusicPlayer。正常運(yùn)行項(xiàng)目需要×××,因?yàn)檫@個(gè)應(yīng)用的音樂資源是從youtube上加載的。在看代碼的時(shí)候需要把無關(guān)代碼快速跳過,把握主線。
現(xiàn)在有同學(xué)可能會(huì)問了,MediaSession框架只能在安卓5系統(tǒng)上使用,但現(xiàn)在安卓5的市場占有率還比較低,如何兼容低版本呢?Google公司在support-v4(21以上版本)中也提供了MediaSessionCompact(android.support.v4.media.session.MediaSessionCompat)兼容包。具體API大同小異。
長年分享Android、Java基礎(chǔ)視頻和課程,以及干貨??!還有老師給大家免費(fèi)視頻課程!
戳鏈接:http://jq.qq.com/?_wv=1027&k=hKlAd4
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。