MediaBrowser 與 MediaController 是本篇的兩個主角,而它們的實作類別分別為 MediaBrowserCompat 以及 MediaControllerCompat,那這兩個類別有什麼功用呢?
MediaBrowserCompat 主要是要連結 MediaBrowserServiceCompat,所以你必須實作 MediaBrowserCompat.ConnectionCallback 來達成連接,那 MediaControllerCompat 最主要就是讓你在你的 UI 上可以操控相關功能。
說明
這邊我們就可以再回來回顧這張圖片,圖中的 MediaController 擔任了 UI 跟 MediaSession 之間的橋樑,而 MediaBrowser 則是擔任跟 MediaBrowserService 的橋樑。
連結到 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