如何使用MediaPlayer-MediaBrowserClient

如何使用MediaPlayer-MediaBrowserClient

MediaBrowser 與 MediaController 是本篇的兩個主角,而它們的實作類別分別為 MediaBrowserCompat 以及 MediaControllerCompat,那這兩個類別有什麼功用呢?

MediaBrowserCompat 主要是要連結 MediaBrowserServiceCompat,所以你必須實作 MediaBrowserCompat.ConnectionCallback 來達成連接,那 MediaControllerCompat 最主要就是讓你在你的 UI 上可以操控相關功能。

說明

這邊我們就可以再回來回顧這張圖片,圖中的 MediaController 擔任了 UI 跟 MediaSession 之間的橋樑,而 MediaBrowser 則是擔任跟 MediaBrowserService 的橋樑。

controller-and-session

連結到 MediaBrowserService

當你的 Activity 被建立的時候,它可以連接到 MediaBrowserService,根據以下步驟一步一步來。

  • onCreate() 建構子內建立一個 MediaBrowserCompat,並且建立 MediaBrowserCompat.ConnectionCallback。
override fun onCreate(savedInstanceState: Bundle?) {
	super.onCreate(savedInstanceState)
  // ...
  // Create MediaBrowserServiceCompat
  mediaBrowser = MediaBrowserCompat(
    this,
    ComponentName(this, MediaPlaybackService::class.java),
    connectionCallbacks,
    null // optional Bundle
  )
}
  • onStart() 連結 MediaBrowserService 透過剛建立的 MediaBrowserCompat.ConnectionCallback 進行連結,在 connectionCallbacks 裡面的 onConnected 內建立我們 MediaController 的實體。
public override fun onStart() {
	super.onStart()
	mediaBrowser.connect()
}
//...
//MediaBrowserCompat.ConnectionCallback
override fun onConnected() {
	// Get a MediaController for the MediaSession.
	mediaController = MediaControllerCompat(context, mediaBrowser.sessionToken).apply {
		registerCallback(MediaControllerCallback())
	}
}
  • onResume() 設定音樂串流的音量控制。
public override fun onResume() {
	super.onResume()
	volumeControlStream = AudioManager.STREAM_MUSIC
}
  • onStop() 結束連結 MediaBrowser 以及解除註冊 MediaController.Callback。
public override fun onStop() {
	super.onStop()
	// (see "stay in sync with the MediaSession")
	MediaControllerCompat.getMediaController(this)?.unregisterCallback(controllerCallback)
	mediaBrowser.disconnect()
}

前面講到實作 MediaBrowserCompat.ConnectionCallback 的內容,我們來看一下這部分怎麼處理?當你建構一個 MediaBrowserCompat 你就同時必須實作 MediaBrowserCompat.ConnectionCallback 並且在 onConnected() 這邊透過 MediaBrowserService 拿到 sessionToken,而且用這個 token 去產出一個 MediaControllerCompat 實體。

你可以透過一個很方便的方法 MediaControllerCompat.setMediaController() 來進行連結 controller。

以下是實作在 MediaBrowserCompat.ConnectionCallback 的 onConnected() 部分程式碼。

// Get the token for the MediaSession
mediaBrowser.sessionToken.also { token ->
	// Create a MediaControllerCompat
	val mediaController = MediaControllerCompat(this@MediaPlayerActivity, token)
	// Save the controller                               
	MediaControllerCompat.setMediaController(this@MediaPlayerActivity, mediaController)
}

media controller 連結到你的 UI

在 ConnectionCallback 的部分程式碼會呼叫到 buildTransportControls() 這個方法內,當你按下 button 以後所處理的事件,透過這個事件就可以控制播放器。

fun buildTransportControls() {
    val mediaController = MediaControllerCompat.getMediaController(this@MediaPlayerActivity)
    // Grab the view for the play/pause button
		R.id.play_pause.apply {
        setOnClickListener {
            // Since this is a play/pause button, you'll need to test the current state
            // and choose the action accordingly

            val pbState = mediaController.playbackState.state
            if (pbState == PlaybackStateCompat.STATE_PLAYING) {
                mediaController.transportControls.pause()
            } else {
                mediaController.transportControls.play()
            }
        }
    }

    // Display the initial state
    val metadata = mediaController.metadata
    val pbState = mediaController.playbackState

    // Register a Callback to stay in sync
    mediaController.registerCallback(controllerCallback)
}

從 PlaybackState 和 Metadata 可以知道 Media Session 目前的狀態,透過以下兩個方法可以得到相關資訊,記得當你的 Activity 結束的時候要解除註冊。

private var controllerCallback = object : MediaControllerCompat.Callback() {

    override fun onMetadataChanged(metadata: MediaMetadataCompat?) {}

    override fun onPlaybackStateChanged(state: PlaybackStateCompat?) {}
}

參考網址

https://developer.android.com/guide/topics/media-apps/audio-app/building-a-mediabrowser-client