連線至「媒體」應用程式的方式有兩種:
MediaControllerMediaBrowser
MediaController
媒體控制器會與媒體工作階段互動,查詢及控制媒體應用程式的播放作業。在 Media3 中,MediaController API 會實作 Player 介面。使用媒體控制器的用戶端應用程式範例包括:
- Android 系統媒體控制項
- Android Wear OS 隨附應用程式
- Android Auto 和 Android Automotive OS
- 語音助理,例如 Google 助理
- 媒體遙控器測試應用程式
媒體控制器在媒體應用程式中也很有用,舉例來說,如果播放器和媒體工作階段位於 Service 與 UI Activity 或 Fragment 不同的位置,媒體控制器就派得上用場。
建立 MediaController
如要建立 MediaController,請先為對應的 MediaSession 建立 SessionToken。Activity 或 Fragment 的 onStart() 方法是執行這項操作的好地方。
Kotlin
val sessionToken = SessionToken(context, ComponentName(context, PlaybackService::class.java))
Java
SessionToken sessionToken = new SessionToken(context, new ComponentName(context, PlaybackService.class));
使用這個 SessionToken 建構 MediaController,即可將控制器連結至指定工作階段。這項作業會非同步執行,因此您應監聽結果,並在結果可用時使用。
Kotlin
val controllerFuture = MediaController.Builder(context, sessionToken).buildAsync() controllerFuture.addListener( { // MediaController is available here with controllerFuture.get() }, MoreExecutors.directExecutor(), )
Java
ListenableFuture<MediaController> controllerFuture = new MediaController.Builder(context, sessionToken).buildAsync(); controllerFuture.addListener( () -> { // MediaController is available here with controllerFuture.get() }, MoreExecutors.directExecutor());
使用 MediaController
MediaController 會實作 Player 介面,因此您可以使用介面中定義的指令,控制已連線 MediaSession 的播放作業。也就是說,在 MediaController 上呼叫 play() 會將指令傳送至已連線的 MediaSession,後者隨後會將指令委派給基礎 Player。
您可以在控制器中新增 Player.Listener,監聽 Player 狀態的變化。如要進一步瞭解如何使用 Player.Listener,請參閱玩家事件指南。
MediaController.Listener 介面會為連線的 MediaSession 定義事件和其他回呼,以及自訂指令。例如:工作階段傳送自訂指令時 (onCustomCommand())、工作階段變更可用工作階段指令時 (onAvailableSessionCommandsChanged()),或控制器與工作階段中斷連線時 (onDisconnected())。
使用 Builder 建構控制器時,可以設定 MediaController.Listener:
Kotlin
val controllerFuture = MediaController.Builder(context, sessionToken) .setListener( object : MediaController.Listener { override fun onCustomCommand( controller: MediaController, command: SessionCommand, args: Bundle, ): ListenableFuture<SessionResult> { // Handle custom command. return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS)) } override fun onDisconnected(controller: MediaController) { // Handle disconnection. } } ) .buildAsync()
Java
ListenableFuture<MediaController> controllerFuture = new MediaController.Builder(context, sessionToken) .setListener( new MediaController.Listener() { @Override public ListenableFuture<SessionResult> onCustomCommand( MediaController controller, SessionCommand command, Bundle args) { // Handle custom command. return Futures.immediateFuture(new SessionResult(SessionResult.RESULT_SUCCESS)); } @Override public void onDisconnected(MediaController controller) { // Handle disconnection. } }) .buildAsync();
與其他元件一樣,請記得在不再需要 MediaController 時釋放,例如在 Activity 或 Fragment 的 onStop() 方法中。
Kotlin
MediaController.releaseFuture(controllerFuture)
Java
MediaController.releaseFuture(controllerFuture);
放開控制器後,系統仍會將所有待處理的指令傳送至工作階段,並只會在處理完這些指令或逾時後 (以先發生者為準),從工作階段服務取消繫結。
MediaBrowser
MediaBrowser 除了 MediaController 提供的功能外,還能瀏覽媒體應用程式 MediaLibraryService 提供的媒體庫。
建立 MediaBrowser
Kotlin
val browserFuture = MediaBrowser.Builder(context, sessionToken).buildAsync() browserFuture.addListener( { // MediaBrowser is available here with browserFuture.get() }, MoreExecutors.directExecutor(), )
Java
ListenableFuture<MediaBrowser> browserFuture = new MediaBrowser.Builder(context, sessionToken).buildAsync(); browserFuture.addListener( () -> { // MediaBrowser is available here with browserFuture.get() }, MoreExecutors.directExecutor());
使用 MediaBrowser
如要開始瀏覽媒體應用程式的內容庫,請先使用 getLibraryRoot() 擷取根節點:
Kotlin
// Get the library root to start browsing the library tree. val rootFuture = mediaBrowser.getLibraryRoot(/* params= */ null) rootFuture.addListener( { // Root node MediaItem is available here with rootFuture.get().value }, MoreExecutors.directExecutor(), )
Java
// Get the library root to start browsing the library tree. ListenableFuture<LibraryResult<MediaItem>> rootFuture = mediaBrowser.getLibraryRoot(/* params= */ null); rootFuture.addListener( () -> { // Root node MediaItem is available here with rootFuture.get().value }, MoreExecutors.directExecutor());
接著,您可以使用 getChildren() 擷取程式庫中 MediaItem 的子項,在媒體庫中瀏覽。舉例來說,如要擷取根節點 MediaItem 的子項:
Kotlin
// Get the library root to start browsing the library tree. val childrenFuture = mediaBrowser.getChildren(rootMediaItem.mediaId, 0, Int.MAX_VALUE, null) childrenFuture.addListener( { // List of children MediaItem nodes is available here with // childrenFuture.get().value }, MoreExecutors.directExecutor(), )
Java
ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> childrenFuture = mediaBrowser.getChildren(rootMediaItem.mediaId, 0, Integer.MAX_VALUE, null); childrenFuture.addListener( () -> { // List of children MediaItem nodes is available here with // childrenFuture.get().value }, MoreExecutors.directExecutor());
顯示其他媒體應用程式的播放控制項
顯示其他媒體應用程式的按鈕 UI 控制項時,請務必遵循該應用程式宣告的媒體按鈕偏好設定。
如要使用 UI 的限制和需求解析應用程式偏好設定,請使用 CommandButton.DisplayConstraints。您可以定義 UI 的限制和限制,而 resolve 方法會提供明確的按鈕清單,其中包含圖示、位置和預期動作。如果使用者點選其中一個按鈕,您可以使用 CommandButton.executeAction 在媒體應用程式中觸發相關動作。
Kotlin
// Get media button preferences from media app val mediaButtonPreferences = controller.getMediaButtonPreferences() // Declare constraints of UI (example: limit overflow button to one) val displayConstraints = DisplayConstraints.Builder().setMaxButtonsForSlot(CommandButton.SLOT_OVERFLOW, 1).build() // Resolve media app preferences with constraints val resolvedButtons = displayConstraints.resolve(mediaButtonPreferences, controller) // Display buttons in UI for (button in resolvedButtons) { generateUiButton( uiPosition = button.slots[0], icon = getIconRes(button.icon), onClick = { button.executeAction(controller) }, ) }
Java
// Get media button preferences from media app List<CommandButton> mediaButtonPreferences = controller.getMediaButtonPreferences(); // Declare constraints of UI (example: limit overflow button to one) DisplayConstraints displayConstraints = new DisplayConstraints.Builder() .setMaxButtonsForSlot(CommandButton.SLOT_OVERFLOW, 1) .build(); // Resolve media app preferences with constraints List<CommandButton> resolvedButtons = displayConstraints.resolve(mediaButtonPreferences, controller); // Display buttons in UI for (CommandButton button : resolvedButtons) { generateUiButton( /* uiPosition= */ button.slots.get(0), /* icon= */ getIconRes(button.icon), /* onClick= */ () -> button.executeAction(controller)); }