如要在應用程式中使用 MediaRouter 架構,您必須取得 MediaRouter
物件的執行個體,並附加 MediaRouter.Callback
物件來監聽轉送事件。透過媒體路徑傳送的內容會通過路線的關聯 MediaRouteProvider
(除了少數特殊情況,例如藍牙輸出裝置)。圖 1 提供用於在裝置之間轉送內容的類別總覽。
注意:如要讓應用程式支援 Google Cast 裝置,請使用 Cast SDK,並且建構應用程式做為投放傳送者。請按照 Cast 說明文件中的指示操作,而不要直接使用 MediaRouter 架構。
媒體路徑按鈕
Android 應用程式應使用媒體路徑按鈕控制媒體路由。MediaRouter 架構提供按鈕的標準介面,可協助使用者辨識及使用有可用的轉送功能。媒體路徑按鈕通常位於應用程式動作列的右側,如圖 2 所示。
當使用者按下媒體路徑按鈕時,可用的媒體路徑會顯示在清單中,如圖 3 所示。
請按照下列步驟建立媒體路徑按鈕:
- 使用 AppCompatActivity
- 定義媒體路徑按鈕選單項目
- 建立 MediaRouteSelector
- 將媒體路徑按鈕新增至動作列
- 在活動生命週期中建立及管理 MediaRouter.Callback 方法
本節說明前四個步驟。下一節將說明回呼方法。
使用 AppCompatActivity
在活動中使用媒體路由器架構時,您應從 AppCompatActivity
擴充活動,並匯入 androidx.appcompat.app
套件。您必須在應用程式開發專案中新增 androidx.appcompat:appcompat 和 androidx.mediarouter:mediarouter。如要進一步瞭解如何在專案中新增支援程式庫,請參閱「開始使用 Android Jetpack」。
注意:請務必使用媒體路由器架構的 androidx
實作。請勿使用舊版 android.media
套件。
定義媒體路徑按鈕選單項目
建立 xml 檔案,用於定義媒體路徑按鈕的選單項目。該項目的動作應為 MediaRouteActionProvider
類別。以下是範例檔案:
// myMediaRouteButtonMenuItem.xml <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" > <item android:id="@+id/media_route_menu_item" android:title="@string/media_route_menu_title" app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider" app:showAsAction="always" /> </menu>
建立 MediaRouteSelector
媒體路徑按鈕選單中顯示的路徑由 MediaRouteSelector
決定。從 AppCompatActivity
擴充活動,並在透過 onCreate() 方法呼叫 MediaRouteSelector.Builder
時建構選取器,如以下程式碼範例所示。請注意,選取器會儲存在類別變數中,而可以加入 MediaControlIntent
物件來指定允許的路線類型:
Kotlin
class MediaRouterPlaybackActivity : AppCompatActivity() { private var mSelector: MediaRouteSelector? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Create a route selector for the type of routes your app supports. mSelector = MediaRouteSelector.Builder() // These are the framework-supported intents .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) .build() } }
Java
public class MediaRouterPlaybackActivity extends AppCompatActivity { private MediaRouteSelector mSelector; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Create a route selector for the type of routes your app supports. mSelector = new MediaRouteSelector.Builder() // These are the framework-supported intents .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) .build(); } }
對大多數應用程式而言,唯一需要的路線類型為 CATEGORY_REMOTE_PLAYBACK
。這個路徑類型會將執行應用程式的裝置視為遙控器。已連結的接收器裝置會處理所有內容資料的擷取、解碼和播放作業。這是支援 Google Cast (例如 Chromecast) 的應用程式運作方式。
部分製造商支援名為「次要輸出」的特殊轉送選項。透過這項轉送,您的媒體應用程式可以擷取和呈現影片或音樂,並直接串流至所選遠端接收器裝置的螢幕和/或喇叭。使用次要輸出內容,將內容傳送至支援無線功能的音樂系統或視訊螢幕。如要啟用這類裝置的探索及選取功能,您必須在 MediaRouteSelector 中加入 CATEGORY_LIVE_AUDIO
或 CATEGORY_LIVE_VIDEO
控制項類別。此外,您也必須建立及處理自己的 Presentation
對話方塊。
將媒體路徑按鈕新增至動作列
定義媒體路徑選單和 MediaRouteSelector 後,您現在可以將媒體路徑按鈕新增至活動。覆寫每個活動的 onCreateOptionsMenu()
方法,以便新增選項選單。
Kotlin
override fun onCreateOptionsMenu(menu: Menu): Boolean { super.onCreateOptionsMenu(menu) // Inflate the menu and configure the media router action provider. menuInflater.inflate(R.menu.sample_media_router_menu, menu) // Attach the MediaRouteSelector to the menu item val mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item) val mediaRouteActionProvider = MenuItemCompat.getActionProvider(mediaRouteMenuItem) as MediaRouteActionProvider // Attach the MediaRouteSelector that you built in onCreate() selector?.also(mediaRouteActionProvider::setRouteSelector) // Return true to show the menu. return true }
Java
@Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); // Inflate the menu and configure the media router action provider. getMenuInflater().inflate(R.menu.sample_media_router_menu, menu); // Attach the MediaRouteSelector to the menu item MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider)MenuItemCompat.getActionProvider( mediaRouteMenuItem); // Attach the MediaRouteSelector that you built in onCreate() mediaRouteActionProvider.setRouteSelector(selector); // Return true to show the menu. return true; }
如要進一步瞭解如何在應用程式中實作動作列,請參閱「動作列」開發人員指南。
您也可以在任何檢視畫面中將媒體路徑按鈕新增為 MediaRouteButton
。您必須使用 setRouteSelector()
方法,將 MediaRouteSelector 附加至按鈕。請參閱 Google Cast 設計檢查清單,瞭解將媒體路徑按鈕整合到應用程式的相關規範。
MediaRouter 回呼
在同一部裝置上執行的所有應用程式都會共用單一 MediaRouter
執行個體及其路徑 (由應用程式的 MediaRouteSelector 篩選每個應用程式)。每個活動都會使用自己的 MediaRouter.Callback
方法實作方式與 MediaRouter 通訊。每當使用者選取、變更或中斷路線時,MediaRouter 就會呼叫回呼方法。
回呼中有幾種方法可以覆寫,以接收轉送事件的相關資訊。實作的 MediaRouter.Callback
類別至少應覆寫 onRouteSelected()
和 onRouteUnselected()
。
由於 MediaRouter 是共用資源,因此您的應用程式需要管理 MediaRouter 回呼,以回應一般的活動生命週期回呼:
- 建立活動時 (
onCreate(Bundle)
) 擷取至MediaRouter
的指標,並在應用程式的生命週期內保留該指標。 - 在活動顯示時將回呼附加至 MediaRouter (
onStart()
),並在活動處於隱藏狀態時將其卸離 (onStop()
)。
下列程式碼範例示範如何建立及儲存回呼物件、如何取得 MediaRouter
的執行個體,以及如何管理回呼。請注意,在 onStart()
中附加回呼時使用了 CALLBACK_FLAG_REQUEST_DISCOVERY
標記。這樣您的 MediaRouteSelector 即可重新整理媒體路徑按鈕的可用路徑清單。
Kotlin
class MediaRouterPlaybackActivity : AppCompatActivity() { private var mediaRouter: MediaRouter? = null private var mSelector: MediaRouteSelector? = null // Variables to hold the currently selected route and its playback client private var mRoute: MediaRouter.RouteInfo? = null private var remotePlaybackClient: RemotePlaybackClient? = null // Define the Callback object and its methods, save the object in a class variable private val mediaRouterCallback = object : MediaRouter.Callback() { override fun onRouteSelected(router: MediaRouter, route: MediaRouter.RouteInfo) { Log.d(TAG, "onRouteSelected: route=$route") if (route.supportsControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { // Stop local playback (if necessary) // ... // Save the new route mRoute = route // Attach a new playback client remotePlaybackClient = RemotePlaybackClient(this@MediaRouterPlaybackActivity, mRoute) // Start remote playback (if necessary) // ... } } override fun onRouteUnselected( router: MediaRouter, route: MediaRouter.RouteInfo, reason: Int ) { Log.d(TAG, "onRouteUnselected: route=$route") if (route.supportsControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { // Changed route: tear down previous client mRoute?.also { remotePlaybackClient?.release() remotePlaybackClient = null } // Save the new route mRoute = route when (reason) { MediaRouter.UNSELECT_REASON_ROUTE_CHANGED -> { // Resume local playback (if necessary) // ... } } } } } // Retain a pointer to the MediaRouter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Get the media router service. mediaRouter = MediaRouter.getInstance(this) ... } // Use this callback to run your MediaRouteSelector to generate the // list of available media routes override fun onStart() { mSelector?.also { selector -> mediaRouter?.addCallback(selector, mediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY) } super.onStart() } // Remove the selector on stop to tell the media router that it no longer // needs to discover routes for your app. override fun onStop() { mediaRouter?.removeCallback(mediaRouterCallback) super.onStop() } ... }
Java
public class MediaRouterPlaybackActivity extends AppCompatActivity { private MediaRouter mediaRouter; private MediaRouteSelector mSelector; // Variables to hold the currently selected route and its playback client private MediaRouter.RouteInfo mRoute; private RemotePlaybackClient remotePlaybackClient; // Define the Callback object and its methods, save the object in a class variable private final MediaRouter.Callback mediaRouterCallback = new MediaRouter.Callback() { @Override public void onRouteSelected(MediaRouter router, RouteInfo route) { Log.d(TAG, "onRouteSelected: route=" + route); if (route.supportsControlCategory( MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){ // Stop local playback (if necessary) // ... // Save the new route mRoute = route; // Attach a new playback client remotePlaybackClient = new RemotePlaybackClient(this, mRoute); // Start remote playback (if necessary) // ... } } @Override public void onRouteUnselected(MediaRouter router, RouteInfo route, int reason) { Log.d(TAG, "onRouteUnselected: route=" + route); if (route.supportsControlCategory( MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){ // Changed route: tear down previous client if (mRoute != null && remotePlaybackClient != null) { remotePlaybackClient.release(); remotePlaybackClient = null; } // Save the new route mRoute = route; if (reason != MediaRouter.UNSELECT_REASON_ROUTE_CHANGED) { // Resume local playback (if necessary) // ... } } } } // Retain a pointer to the MediaRouter @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Get the media router service. mediaRouter = MediaRouter.getInstance(this); ... } // Use this callback to run your MediaRouteSelector to generate the list of available media routes @Override public void onStart() { mediaRouter.addCallback(mSelector, mediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); super.onStart(); } // Remove the selector on stop to tell the media router that it no longer // needs to discover routes for your app. @Override public void onStop() { mediaRouter.removeCallback(mediaRouterCallback); super.onStop(); } ... }
媒體路由器架構也提供 MediaRouteDiscoveryFragment
類別,可處理和移除活動的回呼。
注意:如要編寫音樂播放應用程式,且希望應用程式在背景執行時播放音樂,您必須建構用於播放的 Service
,並從服務的生命週期回呼中呼叫媒體路由器架構。
控制遠端播放路徑
指定遠端播放路徑後,應用程式即為遙控器。路徑另一端的裝置會處理所有內容資料擷取、解碼和播放功能。應用程式 UI 中的控制項使用 RemotePlaybackClient
物件與接收器裝置通訊。
RemotePlaybackClient
類別提供其他管理內容播放的方法。以下是 RemotePlaybackClient
類別的幾個按鍵播放方法:
play()
:播放由Uri
指定的媒體檔案。pause()
:暫停目前正在播放的媒體音軌。resume()
:在暫停指令後繼續播放目前曲目。seek()
:在目前測試群組中的特定位置。release()
:拆除應用程式與遠端播放裝置之間的連線。
您可以使用這些方法,將動作附加到您在應用程式中提供的播放控制項。這些方法大多數也可讓您納入回呼物件,以便監控播放任務或控制要求的進度。
RemotePlaybackClient
類別也支援將多個媒體項目排入佇列,用於播放及管理媒體佇列。
程式碼範例
Android BasicMediaRouter 和 MediaRouter 範例進一步示範如何使用 MediaRouter API。