要在应用中使用 MediaRouter 框架,您必须获取一个实例
MediaRouter
对象的操作,并将
MediaRouter.Callback
对象,用于监听路由事件。
通过媒体路由发送的内容会经过该路由的
关联的 MediaRouteProvider
(少数特殊情况除外,
例如蓝牙输出设备)。图 1 简要展示了
用于在设备之间路由内容的类。
注意:如果您希望应用支持 Google Cast 设备 则应使用 Cast SDK 并将您的应用构建为 Cast 发送器。请按照 Cast 文档 而不是直接使用 MediaRouter 框架
媒体路由按钮
Android 应用应使用媒体路由按钮来控制媒体路由。MediaRouter 框架 为该按钮提供了标准界面,可帮助用户识别和使用路由 。媒体路由按钮通常位于 应用的操作栏,如图 2 所示。
当用户按下媒体路由按钮时,可用的媒体路由会显示在列表中,如图 3 所示。
要创建媒体路由按钮,请按以下步骤操作:
- 使用 AppCompatActivity
- 定义媒体路由按钮菜单项
- 创建 MediaRouteSelector
- 将媒体路由按钮添加到操作栏
- 在 Activity 的生命周期内创建并管理 MediaRouter.Callback 方法
本部分介绍了前四个步骤。下一部分介绍了 Callback 方法。
使用 AppCompatActivity
在 activity 中使用媒体路由器框架时,您应该扩展
从 AppCompatActivity
中获取 activity,并导入
软件包 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
扩展您的 activity
并在创建 activity 时调用 MediaRouteSelector.Builder
构建选择器
调用 onCreate() 方法,如下所示
。请注意,选择器保存在类变量中,允许的路由类型已指定
添加 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,工作。
少数制造商支持称为“辅助输出”的特殊路由选项。通过这种路由,您的
媒体应用可检索、渲染视频或音乐,并将其直接流式传输到所选远程接收器设备上的屏幕和/或扬声器。
使用辅助输出将内容发送到支持无线功能的音乐系统或视频显示屏。要启用发现和
这些设备,您需要将
CATEGORY_LIVE_AUDIO
或
CATEGORY_LIVE_VIDEO
传递给 MediaRouteSelector。您还需要创建和处理自己的 Presentation
对话框。
将媒体路由按钮添加到操作栏
定义媒体路由菜单和 MediaRouteSelector 后,您现在可以将媒体路由按钮添加到 activity。
为每个 activity 替换 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 按应用过滤)。每个 activity 与 MediaRouter 通信
使用自己的 MediaRouter.Callback
实现
方法。每当用户选择、更改或断开路线连接时,MediaRouter 便会调用回调方法。
您可以重写回调中的几个方法,以接收有关
路由事件MediaRouter.Callback
类的实现至少应替换
onRouteSelected()
和
onRouteUnselected()
。
由于 MediaRouter 是共享资源,因此您的应用需要管理其 MediaRouter 回调 以响应常见的 activity 生命周期回调:
- 创建 Activity (
onCreate(Bundle)
) 后,抓取指向MediaRouter
的指针,并在应用的生命周期内持有它。 - 当 activity 变得可见时 (
onStart()
) 将回调附加到 MediaRouter,并在 activity 隐藏时分离它们 (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
类,该类负责添加和
移除 activity 的回调。
注意:如果您正在编写一款音乐播放应用,并希望该应用能够播放
在后台播放音乐时,您必须构建 Service
以进行播放
并从 Service 的生命周期回调调用媒体路由器框架。
控制远程播放路由
在选择远程播放路由时,您的应用会充当遥控器。在路线另一端的设备
处理所有内容数据的检索、解码和播放功能。应用界面中的控件使用
RemotePlaybackClient
对象。
RemotePlaybackClient
类提供了其他方法
用于管理内容播放。以下是一些来自 RemotePlaybackClient
类的主要播放方法:
play()
- 播放特定内容 媒体文件,由Uri
指定。pause()
- 暂停 当前播放的媒体曲目。resume()
- 继续 在执行暂停命令后播放当前曲目。seek()
- 移至特定 在当前曲目中的位置。release()
- 删除 您的应用与远程播放设备之间的连接。
您可以使用这些方法将操作附加到您在 应用。其中大多数方法还允许您包含回调对象,以便您可以监控 播放任务或控制请求的进度。
RemotePlaybackClient
类还支持将
多个媒体项,用于播放和管理媒体队列。
示例代码
Android BasicMediaRouter 和 MediaRouter 进一步演示了如何使用 MediaRouter API。