Sesje multimedialne zapewniają uniwersalny sposób interakcji z odtwarzaczem audio lub wideo. W Media3 domyślnym odtwarzaczem jest klasa ExoPlayer
, która implementuje interfejs Player
. Połączenie sesji multimedialnej z odtwarzaczem umożliwia aplikacji reklamowanie odtwarzania multimediów na zewnątrz i otrzymywanie poleceń odtwarzania ze źródeł zewnętrznych.
Polecenia mogą pochodzić z fizycznych przycisków, takich jak przycisk odtwarzania na słuchawkach lub pilocie do telewizora. Mogą też pochodzić z aplikacji klienckich, które mają kontroler multimediów, np. polecenie „wstrzymaj” dla Asystenta Google. Sesja multimedialna przekazuje te polecenia do odtwarzacza aplikacji multimedialnej.
Kiedy wybrać sesję multimedialną
Gdy zaimplementujesz MediaSession
, użytkownicy będą mogli sterować odtwarzaniem:
- przez słuchawki; Słuchawki często mają przyciski lub funkcje dotykowe, które umożliwiają odtwarzanie i wstrzymywanie multimediów oraz przechodzenie do następnego lub poprzedniego utworu.
- Rozmawiając z Asystentem Google. Często używane polecenie to „OK Google, wstrzymaj”, które wstrzymuje odtwarzanie multimediów na urządzeniu.
- za pomocą zegarka z Wear OS; Ułatwia to dostęp do najczęściej używanych elementów sterujących odtwarzaniem podczas korzystania z telefonu.
- Za pomocą sterowania multimediami. Ten karuzel zawiera elementy sterujące dla każdej aktywnej sesji multimedialnej.
- Na telewizorze. Umożliwia wykonywanie działań za pomocą fizycznych przycisków odtwarzania, sterowania odtwarzaniem na platformie i zarządzania zasilaniem (np. jeśli telewizor, soundbar lub amplituner A/V wyłączy się lub zmieni wejście, odtwarzanie w aplikacji powinno się zatrzymać).
- Za pomocą elementów sterujących multimediami w Androidzie Auto. Umożliwia to bezpieczne sterowanie odtwarzaniem podczas jazdy.
- oraz wszelkie inne procesy zewnętrzne, które mają wpływ na odtwarzanie.
Jest to przydatne w wielu zastosowaniach. W szczególności warto rozważyć użycie MediaSession
, gdy:
- przesyłasz strumieniowo długie filmy, takie jak filmy czy telewizja na żywo;
- odtwarzasz strumieniowo długie treści audio, takie jak podcasty lub playlisty muzyczne;
- Tworzysz aplikację na telewizor.
Nie wszystkie przypadki użycia pasują jednak do MediaSession
. W tych przypadkach możesz użyć tylko Player
:
- Wyświetlasz krótkie treści, które nie wymagają zewnętrznego sterowania ani odtwarzania w tle.
- Nie ma jednego aktywnego filmu, np. użytkownik przewija listę i na ekranie wyświetlanych jest kilka filmów jednocześnie.
- Odtwarzasz jednorazowy film wprowadzający lub wyjaśniający, który użytkownik powinien obejrzeć w całości bez potrzeby korzystania z zewnętrznych elementów sterujących odtwarzaniem.
- Twoje treści są wrażliwe pod względem prywatności i nie chcesz, aby zewnętrzne procesy miały dostęp do metadanych multimediów (np. tryb incognito w przeglądarce).
Jeśli Twój przypadek użycia nie pasuje do żadnego z wymienionych powyżej, zastanów się, czy zgadzasz się na to, aby aplikacja kontynuowała odtwarzanie, gdy użytkownik nie wchodzi aktywnie w interakcję z treścią. Jeśli odpowiedź brzmi „tak”, prawdopodobnie chcesz wybrać MediaSession
. Jeśli odpowiedź jest przecząca, prawdopodobnie zamiast tego chcesz użyć Player
.
Tworzenie sesji multimedialnej
Sesja multimedialna jest powiązana z odtwarzaczem, którym zarządza. Sesję multimedialną możesz utworzyć za pomocą obiektów Context
i Player
. Sesję multimedialną należy utworzyć i zainicjować w razie potrzeby, np. w metodzie cyklu życia onStart()
lub onResume()
elementu Activity
lub Fragment
albo w metodzie onCreate()
elementu Service
, który jest właścicielem sesji multimedialnej i powiązanego z nią odtwarzacza.
Aby utworzyć sesję multimedialną, zainicjuj obiekt Player
i przekaż go do obiektu MediaSession.Builder
w ten sposób:
Kotlin
val player = ExoPlayer.Builder(context).build() val mediaSession = MediaSession.Builder(context, player).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build(); MediaSession mediaSession = new MediaSession.Builder(context, player).build();
Automatyczna obsługa stanu
Biblioteka Media3 automatycznie aktualizuje sesję multimedialną na podstawie stanu odtwarzacza. W związku z tym nie musisz ręcznie obsługiwać mapowania odtwarzacza na sesję.
Różni się to od sesji multimedialnej platformy, w której trzeba było utworzyć i utrzymywać PlaybackState
niezależnie od samego odtwarzacza, np. aby wskazać błędy.
Unikalny identyfikator sesji
Domyślnie funkcja MediaSession.Builder
tworzy sesję z pustym ciągiem znaków jako identyfikatorem sesji. Jest to wystarczające, jeśli aplikacja ma utworzyć tylko jedną instancję sesji, co jest najczęstszym przypadkiem.
Jeśli aplikacja chce zarządzać kilkoma instancjami sesji jednocześnie, musi zadbać o to, aby identyfikator każdej sesji był niepowtarzalny. Identyfikator sesji można ustawić podczas tworzenia sesji za pomocą parametru MediaSession.Builder.setId(String id)
.
Jeśli widzisz IllegalStateException
, a aplikacja ulega awarii z komunikatem o błędzie IllegalStateException: Session ID must be unique. ID=
, prawdopodobnie sesja została nieoczekiwanie utworzona przed zwolnieniem wcześniej utworzonej instancji o tym samym identyfikatorze. Aby uniknąć wycieku sesji z powodu błędu programowania, takie przypadki są wykrywane i zgłaszane przez zgłoszenie wyjątku.
Przyznawanie kontroli innym klientom
Sesja multimedialna jest kluczem do sterowania odtwarzaniem. Umożliwia kierowanie poleceń ze źródeł zewnętrznych do odtwarzacza, który odtwarza multimedia. Mogą to być przyciski fizyczne, np. przycisk odtwarzania na słuchawkach lub pilocie do telewizora, albo polecenia pośrednie, np. polecenie „wstrzymaj” wydane Asystentowi Google. Możesz też przyznać dostęp do systemu Android, aby ułatwić sterowanie powiadomieniami i ekranem blokady, lub do zegarka z Wear OS, aby sterować odtwarzaniem z poziomu tarczy zegarka. Klienci zewnętrzni mogą używać kontrolera multimediów do wydawania poleceń odtwarzania aplikacji multimedialnej. Są one odbierane przez sesję multimedialną, która ostatecznie przekazuje polecenia do odtwarzacza multimediów.

Gdy kontroler ma się połączyć z sesją multimedialną, wywoływana jest metoda
onConnect()
. Na podstawie podanych ControllerInfo
możesz zaakceptować lub odrzucić prośbę. Przykład akceptowania prośby o połączenie znajdziesz w sekcji Deklarowanie niestandardowych poleceń.
Po nawiązaniu połączenia kontroler może wysyłać do sesji polecenia odtwarzania. Sesja przekazuje te polecenia do odtwarzacza. Polecenia odtwarzania i playlisty zdefiniowane w interfejsie Player
są automatycznie obsługiwane przez sesję.
Inne metody wywołania zwrotnego umożliwiają obsługę np. żądań niestandardowych poleceń i modyfikowania playlisty. Te wywołania zwrotne również zawierają obiekt ControllerInfo
, dzięki czemu możesz modyfikować sposób odpowiadania na poszczególne żądania w przypadku każdego kontrolera.
Modyfikowanie playlisty
Sesja multimedialna może bezpośrednio modyfikować playlistę odtwarzacza, jak wyjaśniono w przewodniku ExoPlayera dotyczącym playlist.
Kontrolujący mogą też modyfikować playlistę, jeśli mają dostęp do COMMAND_SET_MEDIA_ITEM
lub COMMAND_CHANGE_MEDIA_ITEMS
.
Podczas dodawania nowych elementów do playlisty odtwarzacz zwykle wymaga MediaItem
instancji z określonym identyfikatorem URI, aby można było je odtworzyć. Domyślnie nowo dodane elementy są automatycznie przekazywane do metod odtwarzacza, takich jak player.addMediaItem
, jeśli mają zdefiniowany identyfikator URI.
Jeśli chcesz dostosować instancje MediaItem
dodane do odtwarzacza, możesz zastąpić onAddMediaItems()
.
Ten krok jest potrzebny, jeśli chcesz obsługiwać kontrolery, które żądają multimediów bez zdefiniowanego identyfikatora URI. Zamiast tego w MediaItem
zwykle ustawia się co najmniej 1 z tych pól, aby opisać żądane media:
MediaItem.id
: ogólny identyfikator określający media.MediaItem.RequestMetadata.mediaUri
: identyfikator URI żądania, który może używać niestandardowego schematu i nie musi być bezpośrednio odtwarzany przez odtwarzacz.MediaItem.RequestMetadata.searchQuery
: tekstowe zapytanie wyszukiwania, np. z Asystenta Google.MediaItem.MediaMetadata
: uporządkowane metadane, takie jak „tytuł” lub „wykonawca”;
Aby uzyskać więcej opcji dostosowywania zupełnie nowych playlist, możesz dodatkowo zastąpić
onSetMediaItems()
element, który pozwala zdefiniować element początkowy i jego pozycję na playliście. Możesz na przykład rozszerzyć pojedynczy żądany element na całą playlistę i polecić odtwarzaczowi rozpoczęcie od indeksu pierwotnie żądanego elementu. A
Przykładową implementację onSetMediaItems()
z tą funkcją znajdziesz w aplikacji demonstracyjnej sesji.
Zarządzanie ustawieniami przycisków multimediów
Każdy kontroler, np. interfejs systemu, Android Auto czy Wear OS, może samodzielnie decydować, które przyciski wyświetlać użytkownikowi. Aby wskazać, które elementy sterujące odtwarzaniem chcesz udostępnić użytkownikowi, możesz określić preferencje dotyczące przycisków multimediów w MediaSession
. Te preferencje to uporządkowana lista instancji CommandButton
, z których każda określa preferencje dotyczące przycisku w interfejsie użytkownika.
Definiowanie przycisków poleceń
Instancje CommandButton
służą do określania preferencji dotyczących przycisków multimediów. Każdy przycisk określa 3 aspekty pożądanego elementu interfejsu:
- Ikona określająca wygląd. Podczas tworzenia
CommandButton.Builder
ikona musi być ustawiona na jedną ze wstępnie zdefiniowanych stałych. Pamiętaj, że nie jest to rzeczywista mapa bitowa ani zasób obrazu. Ogólna stała pomaga kontrolerom wybrać odpowiedni zasób, aby zapewnić spójny wygląd i działanie w ich interfejsie. Jeśli żadna ze stałych wartości ikon nie pasuje do Twojego przypadku użycia, możesz zamiast niej użyćsetCustomIconResId
. - Polecenie określające działanie wywoływane, gdy użytkownik wejdzie w interakcję z przyciskiem. Możesz użyć
setPlayerCommand
w przypadkuPlayer.Command
lubsetSessionCommand
w przypadku wstępnie zdefiniowanego lub niestandardowegoSessionCommand
. - Slot, który określa, gdzie przycisk powinien być umieszczony w interfejsie kontrolera. To pole jest opcjonalne i jest ustawiane automatycznie na podstawie ikony i polecenia. Na przykład pozwala określić, że przycisk powinien być wyświetlany w obszarze nawigacji „do przodu” interfejsu, a nie w domyślnym obszarze „przepełnienia”.
Kotlin
val button = CommandButton.Builder(CommandButton.ICON_SKIP_FORWARD_15) .setSessionCommand(SessionCommand(CUSTOM_ACTION_ID, Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD) .build()
Java
CommandButton button = new CommandButton.Builder(CommandButton.ICON_SKIP_FORWARD_15) .setSessionCommand(new SessionCommand(CUSTOM_ACTION_ID, Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD) .build();
Po ustaleniu preferencji dotyczących przycisków multimediów stosowany jest ten algorytm:
- Dla każdego
CommandButton
w ustawieniach przycisków multimedialnych umieść przycisk w pierwszym dostępnym i dozwolonym slocie. - Jeśli którekolwiek z miejsc środkowych, przednich i tylnych nie są wypełnione przyciskiem, dodaj domyślne przyciski dla tego miejsca.
Możesz użyć CommandButton.DisplayConstraints
, aby wygenerować podgląd sposobu, w jaki preferencje dotyczące przycisków multimedialnych będą rozwiązywane w zależności od ograniczeń wyświetlania interfejsu.
Ustawianie preferencji przycisku multimediów
Najprostszym sposobem ustawienia preferencji dotyczących przycisków multimediów jest zdefiniowanie listy podczas tworzenia MediaSession
. Możesz też zastąpić
MediaSession.Callback.onConnect
ustawienia przycisku multimediów, aby dostosować je do
każdego podłączonego kontrolera.
Kotlin
val mediaSession = MediaSession.Builder(context, player) .setMediaButtonPreferences(ImmutableList.of(likeButton, favoriteButton)) .build()
Java
MediaSession mediaSession = new MediaSession.Builder(context, player) .setMediaButtonPreferences(ImmutableList.of(likeButton, favoriteButton)) .build();
Aktualizowanie ustawień przycisku multimediów po interakcji użytkownika
Po obsłużeniu interakcji z odtwarzaczem możesz zaktualizować przyciski wyświetlane w interfejsie kontrolera. Typowym przykładem jest przycisk przełączania, który zmienia ikonę i działanie po wywołaniu działania powiązanego z tym przyciskiem. Aby zaktualizować ustawienia przycisku multimediów, możesz użyć
MediaSession.setMediaButtonPreferences
, aby zaktualizować ustawienia wszystkich kontrolerów lub konkretnego kontrolera:
Kotlin
// Handle "favoritesButton" action, replace by opposite button mediaSession.setMediaButtonPreferences( ImmutableList.of(likeButton, removeFromFavoritesButton))
Java
// Handle "favoritesButton" action, replace by opposite button mediaSession.setMediaButtonPreferences( ImmutableList.of(likeButton, removeFromFavoritesButton));
Dodawanie niestandardowych poleceń i dostosowywanie domyślnego działania
Dostępne polecenia odtwarzacza można rozszerzyć o polecenia niestandardowe. Można też przechwytywać przychodzące polecenia odtwarzacza i przyciski multimedialne, aby zmienić domyślne działanie.
Deklarowanie i obsługa poleceń niestandardowych
Aplikacje multimedialne mogą definiować niestandardowe polecenia, których można na przykład używać w ustawieniach przycisków multimedialnych. Możesz na przykład zaimplementować przyciski, które pozwolą użytkownikowi zapisać element multimedialny na liście ulubionych. MediaController
wysyła niestandardowe polecenia, a MediaSession.Callback
je odbiera.
Aby zdefiniować niestandardowe polecenia, musisz zastąpić MediaSession.Callback.onConnect()
, aby ustawić dostępne niestandardowe polecenia dla każdego podłączonego kontrolera.
Kotlin
private class CustomMediaSessionCallback: MediaSession.Callback { // Configure commands available to the controller in onConnect() override fun onConnect( session: MediaSession, controller: MediaSession.ControllerInfo ): MediaSession.ConnectionResult { val sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(SessionCommand(SAVE_TO_FAVORITES, Bundle.EMPTY)) .build() return AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build() } }
Java
class CustomMediaSessionCallback implements MediaSession.Callback { // Configure commands available to the controller in onConnect() @Override public ConnectionResult onConnect( MediaSession session, ControllerInfo controller) { SessionCommands sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(new SessionCommand(SAVE_TO_FAVORITES, new Bundle())) .build(); return new AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build(); } }
Aby otrzymywać niestandardowe prośby o polecenia z urządzenia MediaController
, zastąp metodę onCustomCommand()
w klasie Callback
.
Kotlin
private class CustomMediaSessionCallback: MediaSession.Callback { ... override fun onCustomCommand( session: MediaSession, controller: MediaSession.ControllerInfo, customCommand: SessionCommand, args: Bundle ): ListenableFuture<SessionResult> { if (customCommand.customAction == SAVE_TO_FAVORITES) { // Do custom logic here saveToFavorites(session.player.currentMediaItem) return Futures.immediateFuture( SessionResult(SessionResult.RESULT_SUCCESS) ) } ... } }
Java
class CustomMediaSessionCallback implements MediaSession.Callback { ... @Override public ListenableFuture<SessionResult> onCustomCommand( MediaSession session, ControllerInfo controller, SessionCommand customCommand, Bundle args ) { if(customCommand.customAction.equals(SAVE_TO_FAVORITES)) { // Do custom logic here saveToFavorites(session.getPlayer().getCurrentMediaItem()); return Futures.immediateFuture( new SessionResult(SessionResult.RESULT_SUCCESS) ); } ... } }
Możesz śledzić, który kontroler multimediów wysyła żądanie, korzystając z właściwości packageName
obiektu MediaSession.ControllerInfo
, który jest przekazywany do metod Callback
. Dzięki temu możesz dostosować działanie aplikacji w odpowiedzi na dane polecenie, jeśli pochodzi ono z systemu, Twojej aplikacji lub innych aplikacji klienckich.
Dostosowywanie domyślnych poleceń odtwarzacza
Wszystkie domyślne polecenia i obsługa stanu są przekazywane do Player
, które znajduje się na MediaSession
. Aby dostosować działanie polecenia zdefiniowanego w interfejsie Player
, np. play()
lub seekToNext()
, umieść Player
w ForwardingSimpleBasePlayer
przed przekazaniem go do MediaSession
:
Kotlin
val player = (logic to build a Player instance) val forwardingPlayer = object : ForwardingSimpleBasePlayer(player) { // Customizations } val mediaSession = MediaSession.Builder(context, forwardingPlayer).build()
Java
ExoPlayer player = (logic to build a Player instance) ForwardingSimpleBasePlayer forwardingPlayer = new ForwardingSimpleBasePlayer(player) { // Customizations }; MediaSession mediaSession = new MediaSession.Builder(context, forwardingPlayer).build();
Więcej informacji o ForwardingSimpleBasePlayer
znajdziesz w przewodniku po ExoPlayerze w sekcji Dostosowywanie.
Określanie kontrolera, który wysłał polecenie odtwarzacza
Gdy wywołanie metody Player
pochodzi z MediaController
, możesz zidentyfikować źródło za pomocą MediaSession.controllerForCurrentRequest
i uzyskać ControllerInfo
dla bieżącego żądania:
Kotlin
class CallerAwarePlayer(player: Player) : ForwardingSimpleBasePlayer(player) { override fun handleSeek( mediaItemIndex: Int, positionMs: Long, seekCommand: Int, ): ListenableFuture<*> { Log.d( "caller", "seek operation from package ${session.controllerForCurrentRequest?.packageName}", ) return super.handleSeek(mediaItemIndex, positionMs, seekCommand) } }
Java
public class CallerAwarePlayer extends ForwardingSimpleBasePlayer { public CallerAwarePlayer(Player player) { super(player); } @Override protected ListenableFuture<?> handleSeek( int mediaItemIndex, long positionMs, int seekCommand) { Log.d( "caller", "seek operation from package: " + session.getControllerForCurrentRequest().getPackageName()); return super.handleSeek(mediaItemIndex, positionMs, seekCommand); } }
Dostosowywanie obsługi przycisków multimediów
Przyciski multimediów to przyciski sprzętowe znajdujące się na urządzeniach z Androidem i innych urządzeniach peryferyjnych, np. przycisk odtwarzania/pauzy na słuchawkach Bluetooth. Media3 obsługuje zdarzenia przycisków multimedialnych, gdy docierają one do sesji, i wywołuje odpowiednią Player
metodę na odtwarzaczu sesji.
Zalecamy obsługę wszystkich przychodzących zdarzeń przycisków multimedialnych w odpowiedniej metodzie Player
. W bardziej zaawansowanych przypadkach użycia zdarzenia przycisku multimediów można przechwytywać w MediaSession.Callback.onMediaButtonEvent(Intent)
.
Obsługa i raportowanie błędów
Sesja może zgłaszać kontrolerom 2 rodzaje błędów: Poważne błędy to techniczne błędy odtwarzania w odtwarzaczu sesji, które przerywają odtwarzanie. Błędy krytyczne są zgłaszane do kontrolera automatycznie, gdy wystąpią. Błędy niekrytyczne to błędy nietechniczne lub związane z zasadami, które nie przerywają odtwarzania i są wysyłane do kontrolerów ręcznie przez aplikację.
Krytyczne błędy odtwarzania
Odtwarzacz zgłasza do sesji krytyczny błąd odtwarzania, a następnie zgłasza go do kontrolerów, aby wywołać funkcje Player.Listener.onPlayerError(PlaybackException)
i Player.Listener.onPlayerErrorChanged(@Nullable PlaybackException)
.
W takim przypadku stan odtwarzania zmienia się na STATE_IDLE
, a MediaController.getPlaybackError()
zwraca PlaybackException
, które spowodowało zmianę stanu. Kontroler może sprawdzić PlayerException.errorCode
, aby uzyskać informacje o przyczynie błędu.
W przypadku interoperacyjności błąd krytyczny jest replikowany do sesji platformy przez zmianę jej stanu na STATE_ERROR
i ustawienie kodu błędu oraz komunikatu zgodnie z PlaybackException
.
Dostosowywanie błędów krytycznych
Aby przekazywać użytkownikowi zlokalizowane i przydatne informacje, kod błędu, komunikat o błędzie i dodatkowe informacje o błędzie odtwarzania mogą być dostosowywane za pomocą ForwardingPlayer
podczas tworzenia sesji:
Kotlin
val forwardingPlayer = ErrorForwardingPlayer(player) val session = MediaSession.Builder(context, forwardingPlayer).build()
Java
Player forwardingPlayer = new ErrorForwardingPlayer(player); MediaSession session = new MediaSession.Builder(context, forwardingPlayer).build();
Przekazujący odtwarzacz może użyć ForwardingSimpleBasePlayer
, aby przechwycić błąd i dostosować kod błędu, komunikat lub dodatkowe informacje. W ten sam sposób możesz też generować nowe błędy, które nie występują w oryginalnym odtwarzaczu:
Kotlin
class ErrorForwardingPlayer (private val context: Context, player: Player) : ForwardingSimpleBasePlayer(player) { override fun getState(): State { var state = super.getState() if (state.playerError != null) { state = state.buildUpon() .setPlayerError(customizePlaybackException(state.playerError!!)) .build() } return state } fun customizePlaybackException(error: PlaybackException): PlaybackException { val buttonLabel: String val errorMessage: String when (error.errorCode) { PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW -> { buttonLabel = context.getString(R.string.err_button_label_restart_stream) errorMessage = context.getString(R.string.err_msg_behind_live_window) } else -> { buttonLabel = context.getString(R.string.err_button_label_ok) errorMessage = context.getString(R.string.err_message_default) } } val extras = Bundle() extras.putString("button_label", buttonLabel) return PlaybackException(errorMessage, error.cause, error.errorCode, extras) } }
Java
class ErrorForwardingPlayer extends ForwardingSimpleBasePlayer { private final Context context; public ErrorForwardingPlayer(Context context, Player player) { super(player); this.context = context; } @Override protected State getState() { State state = super.getState(); if (state.playerError != null) { state = state.buildUpon() .setPlayerError(customizePlaybackException(state.playerError)) .build(); } return state; } private PlaybackException customizePlaybackException(PlaybackException error) { String buttonLabel; String errorMessage; switch (error.errorCode) { case PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW: buttonLabel = context.getString(R.string.err_button_label_restart_stream); errorMessage = context.getString(R.string.err_msg_behind_live_window); break; default: buttonLabel = context.getString(R.string.err_button_label_ok); errorMessage = context.getString(R.string.err_message_default); break; } Bundle extras = new Bundle(); extras.putString("button_label", buttonLabel); return new PlaybackException(errorMessage, error.getCause(), error.errorCode, extras); } }
Błędy niekrytyczne
Błędy niekrytyczne, które nie wynikają z wyjątku technicznego, mogą być wysyłane przez aplikację do wszystkich lub do określonego kontrolera:
Kotlin
val sessionError = SessionError( SessionError.ERROR_SESSION_AUTHENTICATION_EXPIRED, context.getString(R.string.error_message_authentication_expired), ) // Option 1: Sending a nonfatal error to all controllers. mediaSession.sendError(sessionError) // Option 2: Sending a nonfatal error to the media notification controller only // to set the error code and error message in the playback state of the platform // media session. mediaSession.mediaNotificationControllerInfo?.let { mediaSession.sendError(it, sessionError) }
Java
SessionError sessionError = new SessionError( SessionError.ERROR_SESSION_AUTHENTICATION_EXPIRED, context.getString(R.string.error_message_authentication_expired)); // Option 1: Sending a nonfatal error to all controllers. mediaSession.sendError(sessionError); // Option 2: Sending a nonfatal error to the media notification controller only // to set the error code and error message in the playback state of the platform // media session. ControllerInfo mediaNotificationControllerInfo = mediaSession.getMediaNotificationControllerInfo(); if (mediaNotificationControllerInfo != null) { mediaSession.sendError(mediaNotificationControllerInfo, sessionError); }
Gdy do kontrolera powiadomień o mediach zostanie wysłany błąd niekrytyczny, kod błędu i komunikat o błędzie zostaną powielone w sesji multimedialnej platformy, a wartość PlaybackState.state
nie zostanie zmieniona na STATE_ERROR
.
Otrzymywanie błędów niekrytycznych
MediaController
otrzymuje błąd niekrytyczny, implementując MediaController.Listener.onError
:
Kotlin
val future = MediaController.Builder(context, sessionToken) .setListener(object : MediaController.Listener { override fun onError(controller: MediaController, sessionError: SessionError) { // Handle nonfatal error. } }) .buildAsync()
Java
MediaController.Builder future = new MediaController.Builder(context, sessionToken) .setListener( new MediaController.Listener() { @Override public void onError(MediaController controller, SessionError sessionError) { // Handle nonfatal error. } });