Universal Music Player 源碼解析(一)--MediaSession框架

文章集合:
Universal Music Player 源碼解析(一)--MediaSession框架

Univeral Music Player 源碼解析 -- 讓人頭疼的playback

Universal Music Player 源碼解析(二)--MusicService 和 MediaController

Universal Music Player 源碼分析 (三)-- 其他類分析

MediaSession 框架介紹

大體印象:MediaBrowser 通過調(diào)用getSessionToken()得到一個token,通過這個token,我們的MediaController對象才可以被創(chuàng)建,而MediaSessionMediaController之間通過MediaSession.Token對象相聯(lián)系

以下代碼出自BaseActivity


    private void connectToSession(MediaSessionCompat.Token token) throws RemoteException {
        MediaControllerCompat mediaController = new MediaControllerCompat(this, token);
        MediaControllerCompat.setMediaController(this, mediaController);
        mediaController.registerCallback(mMediaControllerCallback);
...
    }

connectToSession()是在mConnectionCallback中被調(diào)用,


    private final MediaBrowserCompat.ConnectionCallback mConnectionCallback =
        new MediaBrowserCompat.ConnectionCallback() {
            @Override
            public void onConnected() {
                LogHelper.d(TAG, "onConnected");
                try {
                    connectToSession(mMediaBrowser.getSessionToken());
                } catch (RemoteException e) {
                    LogHelper.e(TAG, e, "could not connect media controller");
                    hidePlaybackControls();
                }
            }
        };

同時這個callback作為MediaBrowser的構(gòu)造函數(shù)的參數(shù)被使用,后面會說到這一點(diǎn),根據(jù)函數(shù)見名知意的特點(diǎn),這個回調(diào)將會在mediaBrowser connect的時候被調(diào)用.

繼續(xù)分析,關(guān)于這行代碼:

   MediaControllerCompat.setMediaController(this, mediaController);

跟蹤源碼可以發(fā)現(xiàn)MediaController是嚴(yán)格和Activity對象綁定在一起的,所以才可以通過Activity來獲取MediaController,這個在后面分析MediaSession框架層和UI的聯(lián)系的時候會再次說明.

   MediaControllerCompat 
controllerCompat = MediaControllerCompat.getMediaController(this);

之前說過,MediaBrowser是通過構(gòu)造函數(shù)創(chuàng)建的:

mMediaBrowser = new MediaBrowserCompat
(this
,new ComponentName(this, MusicService.class),
,mConnectionCallback,
 null);

簡單來說,這個構(gòu)造函數(shù)傳入了一個MusicService,跟蹤源碼的話,這個MusicService將會在mediaBrowser的connect()中啟動

  public void connect() {
        mImpl.connect();
    }

mImpl是一個MediaBrowserImpl對象


 final Intent intent = new Intent(MediaBrowserServiceCompat.SERVICE_INTERFACE); intent.setComponent(mServiceComponent);
 mServiceConnection = new MediaServiceConnection();
      boolean bound = false;
           try {
         bound = mContext.bindService(intent, mServiceConnection,
      Context.BIND_AUTO_CREATE);

MusicService將會通過bindService的方式啟動,
傳進(jìn)去的另外一個mConnectionCallbackonConnected()將會在回調(diào)之前獲取到一個Token對象.

再說一下真正關(guān)心的MediaSession
以下代碼出自MusicService
MusicService繼承了MediaBrowserServiceCompat

 //the string paras is tag for debugging purpose
        mSession = new MediaSessionCompat(this, "MusicService");
        setSessionToken(mSession.getSessionToken());
        mSession.setCallback(mPlaybackManager.getMediaSessionCallback());
        mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
                MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);

先看這行代碼:

 setSessionToken(mSession.getSessionToken());

同樣這個token是根據(jù)``MusicService`綁定的,之后可以根據(jù)MusicService的對象取出來

  MediaSessionCompat.Token freshToken 
= mService.getSessionToken();

同時,MediaSession還有一個很重要的功能就是管理playback

  mSession.setCallback(mPlaybackManager.getMediaSessionCallback());
private class MediaSessionCallback extends MediaSessionCompat.Callback {
        @Override
        public void onPlay() {
            LogHelper.d(TAG, "play");
            if (mQueueManager.getCurrentMusic() == null) {
                mQueueManager.setRandomQueue();
            }
            handlePlayRequest();
        }

        @Override
        public void onSkipToQueueItem(long queueId) {
            LogHelper.d(TAG, "OnSkipToQueueItem:" + queueId);
            mQueueManager.setCurrentQueueItem(queueId);
            mQueueManager.updateMetadata();
        }

        @Override
        public void onSeekTo(long position) {
            LogHelper.d(TAG, "onSeekTo:", position);
            mPlayback.seekTo((int) position);
        }

        @Override
        public void onPlayFromMediaId(String mediaId, Bundle extras) {
            LogHelper.d(TAG, "playFromMediaId mediaId:", mediaId, "  extras=", extras);
            mQueueManager.setQueueFromMusic(mediaId);
            handlePlayRequest();
        }

        @Override
        public void onPause() {
            LogHelper.d(TAG, "pause. current state=" + mPlayback.getState());
            handlePauseRequest();
        }

        @Override
        public void onStop() {
            LogHelper.d(TAG, "stop. current state=" + mPlayback.getState());
            handleStopRequest(null);
        }

        @Override
        public void onSkipToNext() {
            LogHelper.d(TAG, "skipToNext");
            if (mQueueManager.skipQueuePosition(1)) {
                handlePlayRequest();
            } else {
                handleStopRequest("Cannot skip");
            }
            mQueueManager.updateMetadata();
        }

        @Override
        public void onSkipToPrevious() {
            if (mQueueManager.skipQueuePosition(-1)) {
                handlePlayRequest();
            } else {
                handleStopRequest("Cannot skip");
            }
            mQueueManager.updateMetadata();
        }

        @Override
        public void onCustomAction(@NonNull String action, Bundle extras) {
            if (CUSTOM_ACTION_THUMBS_UP.equals(action)) {
                LogHelper.i(TAG, "onCustomAction: favorite for current track");
                MediaSessionCompat.QueueItem currentMusic = mQueueManager.getCurrentMusic();
                if (currentMusic != null) {
                    String mediaId = currentMusic.getDescription().getMediaId();
                    if (mediaId != null) {
                        String musicId = MediaIDHelper.extractMusicIDFromMediaID(mediaId);
                        mMusicProvider.setFavorite(musicId, !mMusicProvider.isFavorite(musicId));
                    }
                }
                // playback state needs to be updated because the "Favorite" icon on the
                // custom action will change to reflect the new favorite state.
                updatePlaybackState(null);
            } else {
                LogHelper.e(TAG, "Unsupported action: ", action);
            }
        }

  .....
    }

在這個回調(diào)中就會調(diào)用PlaybackManager中實(shí)現(xiàn)了Callback類的中的方法

我看了很多關(guān)于這個項(xiàng)目的解析,很多前輩對mediaBrowser的解析和這個類在這個框架中的作用是很少的,所以總結(jié)為以下圖

image.png

下一篇將會將重點(diǎn)放在model層,關(guān)于數(shù)據(jù)是怎么獲取和如何使用MediaIDHelper解析的

links:
如何閱讀Android hide api
MediaSession框架介紹

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末皆警,一起剝皮案震驚了整個濱河市锐峭,隨后出現(xiàn)的幾起案子疑务,更是在濱河造成了極大的恐慌,老刑警劉巖诸尽,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異锌半,居然都是意外死亡扮惦,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門尿扯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來求晶,“玉大人,你說我怎么就攤上這事姜胖∮В” “怎么了淀散?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵右莱,是天一觀的道長。 經(jīng)常有香客問我档插,道長慢蜓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任郭膛,我火速辦了婚禮晨抡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘则剃。我一直安慰自己耘柱,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布棍现。 她就那樣靜靜地躺著调煎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪己肮。 梳的紋絲不亂的頭發(fā)上士袄,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天悲关,我揣著相機(jī)與錄音,去河邊找鬼娄柳。 笑死寓辱,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赤拒。 我是一名探鬼主播秫筏,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼挎挖!你這毒婦竟也來了跳昼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤肋乍,失蹤者是張志新(化名)和其女友劉穎鹅颊,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體墓造,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡堪伍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了觅闽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片帝雇。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蛉拙,靈堂內(nèi)的尸體忽然破棺而出尸闸,到底是詐尸還是另有隱情,我是刑警寧澤孕锄,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布吮廉,位于F島的核電站,受9級特大地震影響畸肆,放射性物質(zhì)發(fā)生泄漏宦芦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一轴脐、第九天 我趴在偏房一處隱蔽的房頂上張望调卑。 院中可真熱鬧,春花似錦大咱、人聲如沸恬涧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽溯捆。三九已至,卻和暖如春餐抢,著一層夾襖步出監(jiān)牢的瞬間现使,已是汗流浹背低匙。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留碳锈,地道東北人顽冶。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像售碳,于是被迫代替她去往敵國和親强重。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容