Aby korzystać z platformy MediaRouter w aplikacji, musisz uzyskać instancję obiektu MediaRouter
i dołączyć obiekt MediaRouter.Callback
do nasłuchiwania zdarzeń routingu.
Treści wysyłane przez trasę multimediów przechodzą przez powiązany z nią element MediaRouteProvider
(z wyjątkiem kilku szczególnych przypadków, np. przez urządzenie wyjściowe Bluetooth). Rysunek 1 przedstawia ogólny widok klas używanych do kierowania treści między urządzeniami.
Uwaga: jeśli chcesz, aby aplikacja obsługiwała urządzenia Google Cast, skorzystaj z pakietu SDK Cast i utwórz aplikację jako nadawca. Postępuj zgodnie z instrukcjami podanymi w dokumentacji przesyłania zamiast bezpośrednio używać platformy MediaRouter.
Przycisk kierowania multimediów
Aplikacje na Androida powinny używać przycisku trasy multimediów do sterowania routingiem multimediów. Platforma MediaRouter zapewnia standardowy interfejs przycisku, który ułatwia użytkownikom rozpoznawanie dostępnego routingu i korzystanie z niego. Przycisk trasy multimediów znajduje się zwykle po prawej stronie paska działań aplikacji, jak widać na ilustracji 2.
Gdy użytkownik kliknie przycisk trasy multimediów, dostępne trasy multimediów zostaną wyświetlone na liście, tak jak to widać na ilustracji 3.
Aby utworzyć przycisk trasy multimediów, wykonaj te czynności:
- Używanie obiektu AppCompatActivity
- Zdefiniuj element menu Zdefiniuj element menu kierowania multimediów
- Tworzenie obiektu MediaRouteSelector
- Dodawanie przycisku kierowania multimediów do paska działań
- Tworzenie metod MediaRouter.Callback w cyklu życia aktywności i zarządzanie nimi
W tej sekcji opisujemy cztery pierwsze kroki. W następnej sekcji opisujemy metody wywołania zwrotnego.
Używanie obiektu AppCompatActivity
Jeśli w działaniu używasz platformy routera multimediów, musisz rozszerzyć działanie z AppCompatActivity
i zaimportować pakiet androidx.appcompat.app
. Do projektu, w którym się znajdujesz, musisz dodać biblioteki obsługi androidx.appcompat:appcompat i androidx.mediarouter:mediarouter. Więcej informacji o dodawaniu bibliotek pomocy do projektu znajdziesz w artykule Pierwsze kroki z Androidem Jetpack.
Uwaga: pamiętaj, aby użyć implementacji platformy routera multimediów androidx
. Nie używaj starszego pakietu android.media
.
Zdefiniuj element menu Zdefiniuj element menu kierowania multimediów
Utwórz plik XML definiujący pozycję menu przycisku trasy multimediów.
Akcją elementu powinna być klasa MediaRouteActionProvider
.
Oto przykładowy plik:
// 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>
Tworzenie obiektu MediaRouteSelector
Trasy widoczne w menu przycisku trasy multimediów są określane znakiem MediaRouteSelector
.
Rozszerz aktywność z AppCompatActivity
i utwórz selektor po utworzeniu aktywności wywołującej metodę MediaRouteSelector.Builder
z metody onCreate() jak w przykładzie poniżej. Pamiętaj, że selektor jest zapisany w zmiennej klasy, a dozwolone typy tras określa się, dodając obiekty 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(); } }
W przypadku większości aplikacji jedynym wymaganym typem trasy jest CATEGORY_REMOTE_PLAYBACK
. Ten typ trasy traktuje urządzenie, na którym działa Twoja aplikacja, jako pilota.
Podłączony odbiornik zajmuje się pobieraniem, dekodowaniem i odtwarzaniem wszystkich danych dotyczących treści.
W ten sposób działają aplikacje obsługujące Google Cast, takie jak Chromecast.
Niektórzy producenci udostępniają specjalną opcję routingu o nazwie „dodatkowe urządzenie wyjściowe”. Dzięki temu ustawieniu routingu aplikacja do multimediów pobiera, renderuje i przesyła strumieniowo filmy oraz muzykę bezpośrednio na ekran lub głośniki wybranego odbiornika zdalnego.
Za pomocą dodatkowego wyjścia możesz wysyłać treści do bezprzewodowych systemów muzycznych lub wyświetlaczy wideo. Aby umożliwić wykrywanie i wybieranie tych urządzeń, musisz do obiektu MediaRouteSelector dodać kategorię elementów sterujących CATEGORY_LIVE_AUDIO
lub CATEGORY_LIVE_VIDEO
. Musisz też utworzyć i obsługiwać własne okno Presentation
.
Dodawanie przycisku kierowania multimediów do paska działań
Po zdefiniowaniu menu trasy multimediów i zdefiniowania opcji MediaRouteSelector możesz teraz dodać do aktywności przycisk trasy multimediów.
Zastąp metodę onCreateOptionsMenu()
w przypadku każdej aktywności, aby dodać menu opcji.
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; }
Więcej informacji o implementowaniu paska działań w aplikacji znajdziesz w przewodniku dla programistów dotyczącym paska działań.
Możesz też dodać przycisk trasy multimediów jako MediaRouteButton
w dowolnym widoku danych. Musisz dołączyć do przycisku obiekt MediaRouteSelector za pomocą metody setRouteSelector()
. Zapoznaj się z listą kontrolną projektowania Google Cast, by dowiedzieć się, jak dodać przycisk trasy multimediów do swojej aplikacji.
Wywołania zwrotne MediaRouter
Wszystkie aplikacje uruchomione na tym samym urządzeniu mają 1 instancję MediaRouter
i jej trasy (odfiltrowane według aplikacji MediaRouteSelector). Każde działanie komunikuje się z MediaRouter za pomocą własnej implementacji metod MediaRouter.Callback
. MediaRouter wywołuje metody wywołania zwrotnego za każdym razem, gdy użytkownik wybiera, zmienia lub rozłącza trasę.
W wywołaniu zwrotnym jest kilka metod, które możesz zastąpić, aby otrzymywać informacje o zdarzeniach routingu. Implementacja klasy MediaRouter.Callback
powinna zastąpić klasy onRouteSelected()
i onRouteUnselected()
.
MediaRouter jest zasobem współdzielonym, więc Twoja aplikacja musi zarządzać wywołaniami zwrotnymi MediaRouter w odpowiedzi na zwykłe wywołania zwrotne cyklu życia aktywności:
- Po utworzeniu aktywności (
onCreate(Bundle)
) chwyć wskaźnik do elementuMediaRouter
i przytrzymaj go przez cały czas istnienia aplikacji. - Dołącz wywołania zwrotne do MediaRouter, gdy aktywność staje się widoczna (
onStart()
), i odłącz je, gdy jest ukryta (onStop()
).
Poniższy przykładowy kod pokazuje, jak utworzyć i zapisać obiekt wywołania zwrotnego, jak uzyskać instancję MediaRouter
i jak zarządzać wywołaniami zwrotnymi.
Zwróć uwagę na użycie flagi CALLBACK_FLAG_REQUEST_DISCOVERY
podczas dołączania wywołań zwrotnych w onStart()
.
Pozwoli to obiektowi MediaRouteSelector na odświeżenie listy dostępnych tras przycisku trasy multimediów.
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(); } ... }
Platforma routera multimediów udostępnia też klasę MediaRouteDiscoveryFragment
, która ułatwia dodawanie i usuwanie wywołania zwrotnego dla działania.
Uwaga: jeśli tworzysz aplikację do odtwarzania muzyki i chcesz, aby aplikacja odtwarzała muzykę, gdy działa w tle, musisz utworzyć Service
do odtwarzania i wywołać platformę routera multimediów za pomocą wywołań zwrotnych cyklu życia usługi.
Sterowanie trasą odtwarzania zdalnego
Gdy wybierzesz trasę zdalnego odtwarzania, aplikacja będzie pełnić funkcję pilota. Urządzenie po drugiej stronie trasy obsługuje wszystkie funkcje pobierania, dekodowania i odtwarzania danych o treści. Elementy sterujące w interfejsie aplikacji komunikują się z urządzeniem odbierającym za pomocą obiektu RemotePlaybackClient
.
Klasa RemotePlaybackClient
udostępnia dodatkowe metody zarządzania odtwarzaniem treści. Oto kilka najważniejszych metod odtwarzania z klasy RemotePlaybackClient
:
play()
– odtwarza określony plik multimedialny określony przezUri
.pause()
– wstrzymaj odtwarzaną aktualnie ścieżkę multimediów.resume()
– kontynuuj odtwarzanie bieżącego utworu po wykonaniu polecenia wstrzymania.seek()
– przejście do konkretnego miejsca w bieżącej ścieżce.release()
– przerwij połączenie aplikacji z urządzeniem zdalnego odtwarzania.
Za pomocą tych metod możesz dołączać działania do elementów sterujących odtwarzaniem, które są dostępne w Twojej aplikacji. Większość z nich pozwala też dołączać obiekt wywołania zwrotnego, aby umożliwić monitorowanie postępu zadania odtwarzania lub żądania kontrolnego.
Klasa RemotePlaybackClient
obsługuje też dodawanie do kolejki wielu elementów multimedialnych na potrzeby odtwarzania i zarządzania kolejką multimediów.
Kod demonstracyjny
Przykłady korzystania z Android BasicMediaRouter i MediaRouter dodatkowo pokazują wykorzystanie interfejsu MediaRouter API.