Co najmniej 2 aplikacje na Androida mogą jednocześnie odtwarzać dźwięk w tym samym strumieniu wyjściowym, a system wszystko miksuje. Choć jest to imponujące pod względem technicznym, może być bardzo irytujące dla użytkownika. Aby uniknąć jednoczesnego odtwarzania muzyki przez wszystkie aplikacje, Android wprowadza koncepcję fokusowania dźwięku. Tylko jedna aplikacja może mieć fokus audio w danym momencie.
Gdy aplikacja musi odtwarzać dźwięk, powinna poprosić o skupienie dźwięku. Gdy ma fokus, może odtwarzać dźwięk. Jednak po uzyskaniu fokusu audio możesz nie być w stanie utrzymać go do końca odtwarzania. Inna aplikacja może poprosić o skupienie, co spowoduje przerwanie Twojego dostępu do skupienia dźwięku. W takim przypadku aplikacja powinna wstrzymać odtwarzanie lub zmniejszyć głośność, aby użytkownicy mogli łatwiej usłyszeć nowe źródło dźwięku.
W wersjach Androida starszych niż 12 (poziom interfejsu API 31) system nie zarządza fokusem dźwięku. Dlatego zachęcamy deweloperów aplikacji do przestrzegania wytycznych dotyczących fokusu audio, ale jeśli aplikacja nadal odtwarza dźwięk głośno nawet po utracie fokusu audio na urządzeniu z Androidem 11 (API na poziomie 30) lub starszym, system nie może temu zapobiec. Takie zachowanie aplikacji obniża komfort użytkowników i często prowadzi do odinstalowania przez nich aplikacji, która działa nieprawidłowo.
Dobrze zaprojektowana aplikacja audio powinna zarządzać fokusem dźwięku zgodnie z tymi ogólnymi wytycznymi:
Zadzwoń pod numer
requestAudioFocus()
bezpośrednio przed rozpoczęciem gry i sprawdź, czy połączenie zostało nawiązaneAUDIOFOCUS_REQUEST_GRANTED
. Wykonaj połączenie zrequestAudioFocus()
wonPlay()
wywołaniu zwrotnym sesji multimedialnej.Gdy inna aplikacja uzyska fokus dźwięku, zatrzymaj lub wstrzymaj odtwarzanie albo zmniejsz głośność.
Gdy odtwarzanie się zatrzyma (np. gdy aplikacja nie ma już nic do odtworzenia), zrezygnuj z fokusowania dźwięku. Aplikacja nie musi rezygnować z fokusu audio, jeśli użytkownik wstrzyma odtwarzanie, ale może je później wznowić.
Użyj
AudioAttributes
, aby opisać rodzaj dźwięku odtwarzanego przez aplikację. Na przykład w przypadku aplikacji, które odtwarzają mowę, podaj wartośćCONTENT_TYPE_SPEECH
.
Fokus dźwięku jest obsługiwany w różny sposób w zależności od wersji Androida:
- Android 12 (poziom 31 interfejsu API) lub nowszy
- Fokus dźwięku jest zarządzany przez system. Gdy inna aplikacja poprosi o aktywność audio, system wymusi wyciszenie odtwarzania dźwięku z aplikacji. System wycisza też odtwarzanie dźwięku, gdy odbierasz połączenie przychodzące.
- Android 8.0 (poziom 26 interfejsu API) do Androida 11 (poziom 30 interfejsu API)
- Fokus dźwięku nie jest zarządzany przez system, ale obejmuje pewne zmiany, które zostały wprowadzone w Androidzie 8.0 (interfejs API na poziomie 26).
- Android 7.1 (poziom 25 interfejsu API) lub starszy
- System nie zarządza fokusem audio, a aplikacje zarządzają nim za pomocą funkcji
requestAudioFocus()
iabandonAudioFocus()
.
Skupienie dźwięku na Androidzie 12 i nowszym
Aplikacja multimedialna lub gra, która korzysta z fokusowania dźwięku, nie powinna odtwarzać dźwięku po utracie fokusu. W Androidzie 12 (API na poziomie 31) i nowszym system wymusza takie zachowanie. Gdy aplikacja zażąda fokusu audio, a inna aplikacja ma fokus i odtwarza dźwięk, system wymusza wyciszenie odtwarzającej aplikacji. Dodanie efektu wygaszania zapewnia płynniejsze przejście z jednej aplikacji do drugiej.
Efekt wygaszania występuje, gdy są spełnione te warunki:
Pierwsza aplikacja, która jest obecnie odtwarzana, spełnia wszystkie te kryteria:
- Aplikacja ma atrybut użycia
AudioAttributes.USAGE_MEDIA
lubAudioAttributes.USAGE_GAME
. - Aplikacja poprawnie poprosiła o skupienie dźwięku z parametrem
AudioManager.AUDIOFOCUS_GAIN
. - Aplikacja nie odtwarza dźwięku z typem treści
AudioAttributes.CONTENT_TYPE_SPEECH
.
- Aplikacja ma atrybut użycia
Druga aplikacja prosi o aktywność audio z ustawieniem
AudioManager.AUDIOFOCUS_GAIN
.
Gdy te warunki są spełnione, system audio wycisza pierwszą aplikację. Po zakończeniu wyciszania system powiadamia pierwszą aplikację o utracie fokusu. Odtwarzacze aplikacji pozostają wyciszone, dopóki aplikacja nie poprosi ponownie o aktywność audio.
Dotychczasowe zachowania związane z priorytetem dźwięku
Pamiętaj też o tych przypadkach, w których następuje zmiana źródła dźwięku.
Automatyczne wyciszanie
Automatyczne wyciszanie tła (tymczasowe zmniejszanie poziomu dźwięku jednej aplikacji, aby wyraźnie słyszeć inną) zostało wprowadzone w Androidzie 8.0 (poziom interfejsu API 26).
Dzięki temu, że system implementuje wyciszanie, nie musisz go implementować w swojej aplikacji.
Automatyczne wyciszanie następuje również wtedy, gdy powiadomienie dźwiękowe przejmuje fokus z odtwarzanej aplikacji. Początek odtwarzania powiadomienia jest zsynchronizowany z końcem wyciszania.
Automatyczne ściszanie następuje, gdy są spełnione te warunki:
Pierwsza aktualnie odtwarzana aplikacja spełnia wszystkie te kryteria:
- Aplikacja poprawnie poprosiła o skupienie dźwięku z dowolnym typem wzmocnienia skupienia.
- Aplikacja nie odtwarza dźwięku z typem treści
AudioAttributes.CONTENT_TYPE_SPEECH
. - Aplikacja nie ustawiła
AudioFocusRequest.Builder.setWillPauseWhenDucked(true)
.
Druga aplikacja prosi o aktywność audio za pomocą metody
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
.
Gdy te warunki są spełnione, system audio wycisza wszystkich aktywnych odtwarzaczy pierwszej aplikacji, gdy druga aplikacja jest aktywna. Gdy druga aplikacja przestanie być aktywna, zostanie odpięta. Pierwsza aplikacja nie otrzymuje powiadomienia o utracie fokusu, więc nie musi nic robić.
Pamiętaj, że automatyczne wyciszanie nie jest wykonywane, gdy użytkownik słucha treści mówionych, ponieważ może wtedy przegapić część programu. Na przykład wskazówki głosowe dotyczące trasy nie są wyciszane.
Wyciszanie odtwarzania dźwięku podczas połączeń przychodzących
Niektóre aplikacje nie działają prawidłowo i nadal odtwarzają dźwięk podczas rozmów telefonicznych. W takiej sytuacji użytkownik musi znaleźć i wyciszyć lub zamknąć aplikację, która zakłóca połączenie, aby móc je usłyszeć. Aby temu zapobiec, system może wyciszyć dźwięk z innych aplikacji podczas połączenia przychodzącego. System wywołuje tę funkcję, gdy przychodzi połączenie telefoniczne, a aplikacja spełnia te warunki:
- Aplikacja ma atrybut użycia
AudioAttributes.USAGE_MEDIA
lubAudioAttributes.USAGE_GAME
. - Aplikacja przesłała udane żądanie fokusu dźwięku (dowolnego typu) i odtwarza dźwięk.
Jeśli aplikacja będzie odtwarzać treści podczas połączenia, odtwarzanie zostanie wyciszone do momentu zakończenia połączenia. Jeśli jednak aplikacja zacznie odtwarzać dźwięk podczas połączenia, nie zostanie wyciszona, ponieważ zakłada się, że użytkownik celowo rozpoczął odtwarzanie.
Skupienie dźwięku w Androidzie w wersji od 8.0 do 11
Począwszy od Androida 8.0 (interfejs API na poziomie 26), gdy wywołujesz funkcję requestAudioFocus()
, musisz podać parametr AudioFocusRequest
. Plik AudioFocusRequest
zawiera informacje o kontekście audio i możliwościach aplikacji. System wykorzystuje te informacje do automatycznego zarządzania uzyskiwaniem i utratą fokusu audio. Aby zwolnić aktywność audio, wywołaj metodę
abandonAudioFocusRequest()
która przyjmuje też argument AudioFocusRequest
. Używaj tej samej instancji AudioFocusRequest
zarówno podczas wysyłania żądania, jak i rezygnowania z koncentracji.
Aby utworzyć AudioFocusRequest
, użyj
AudioFocusRequest.Builder
. Żądanie fokusu musi zawsze określać typ żądania, dlatego typ jest uwzględniony w konstruktorze narzędzia do tworzenia. Użyj metod narzędzia do tworzenia, aby ustawić pozostałe pola żądania.
Pole FocusGain
jest wymagane, a wszystkie pozostałe pola są opcjonalne.
Metoda | Uwagi |
---|---|
setFocusGain()
|
To pole jest wymagane w każdym żądaniu. Przyjmuje te same wartości co durationHint używane w wywołaniu requestAudioFocus() przed Androidem 8.0:AUDIOFOCUS_GAIN , AUDIOFOCUS_GAIN_TRANSIENT ,AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK lub AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE .
|
setAudioAttributes()
|
AudioAttributes opisuje przypadek użycia aplikacji. System sprawdza je, gdy aplikacja uzyskuje i traci fokus audio. Atrybuty zastępują pojęcie typu strumienia. W Androidzie 8.0 (poziom interfejsu API 26) i nowszych typy strumieni dla wszystkich operacji innych niż sterowanie głośnością są wycofane. Użyj tych samych atrybutów w żądaniu fokusu, których używasz w odtwarzaczu audio (jak pokazano w przykładzie poniżej tej tabeli).
Użyj
Jeśli nie podasz tu żadnej wartości, |
setWillPauseWhenDucked()
|
Gdy inna aplikacja poprosi o skupienie za pomocą funkcji
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK , aplikacja, która ma skupienie, zwykle nie otrzymuje wywołania zwrotnego
onAudioFocusChange() , ponieważ system może samodzielnie wyciszyć dźwięk. Jeśli chcesz wstrzymać odtwarzanie, a nie zmniejszyć głośność, wywołaj funkcję setWillPauseWhenDucked(true) i utwórz oraz ustaw OnAudioFocusChangeListener zgodnie z opisem w sekcji automatyczne zmniejszanie głośności.
|
setAcceptsDelayedFocusGain()
|
Prośba o aktywność audio może się nie powieść, gdy jest ona zablokowana przez inną aplikację.
Ta metoda umożliwia opóźnione uzyskanie aktywności: możliwość
asynchronicznego uzyskania aktywności, gdy stanie się ona dostępna.
Pamiętaj, że opóźnione uzyskanie aktywności działa tylko wtedy, gdy w żądaniu audio podasz też
|
setOnAudioFocusChangeListener()
|
Element OnAudioFocusChangeListener jest wymagany tylko wtedy, gdy w żądaniu podasz też element willPauseWhenDucked(true) lub setAcceptsDelayedFocusGain(true) .
Są 2 metody ustawiania odbiornika: jedna z argumentem handlera i jedna bez niego. Obsługa to wątek, w którym działa odbiornik. Jeśli nie określisz modułu obsługi, zostanie użyty moduł obsługi powiązany z głównym |
Ten przykład pokazuje, jak za pomocą AudioFocusRequest.Builder
utworzyć AudioFocusRequest
oraz wysłać żądanie i zrezygnować z fokusowania dźwięku:
Kotlin
// initializing variables for audio focus and playback management audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).run { setAudioAttributes(AudioAttributes.Builder().run { setUsage(AudioAttributes.USAGE_GAME) setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) build() }) setAcceptsDelayedFocusGain(true) setOnAudioFocusChangeListener(afChangeListener, handler) build() } val focusLock = Any() var playbackDelayed = false var playbackNowAuthorized = false // requesting audio focus and processing the response val res = audioManager.requestAudioFocus(focusRequest) synchronized(focusLock) { playbackNowAuthorized = when (res) { AudioManager.AUDIOFOCUS_REQUEST_FAILED -> false AudioManager.AUDIOFOCUS_REQUEST_GRANTED -> { playbackNow() true } AudioManager.AUDIOFOCUS_REQUEST_DELAYED -> { playbackDelayed = true false } else -> false } } // implementing OnAudioFocusChangeListener to react to focus changes override fun onAudioFocusChange(focusChange: Int) { when (focusChange) { AudioManager.AUDIOFOCUS_GAIN -> if (playbackDelayed || resumeOnFocusGain) { synchronized(focusLock) { playbackDelayed = false resumeOnFocusGain = false } playbackNow() } AudioManager.AUDIOFOCUS_LOSS -> { synchronized(focusLock) { resumeOnFocusGain = false playbackDelayed = false } pausePlayback() } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { synchronized(focusLock) { // only resume if playback is being interrupted resumeOnFocusGain = isPlaying() playbackDelayed = false } pausePlayback() } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { // ... pausing or ducking depends on your app } } }
Java
// initializing variables for audio focus and playback management audioManager = (AudioManager) Context.getSystemService(Context.AUDIO_SERVICE); playbackAttributes = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_GAME) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build(); focusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) .setAudioAttributes(playbackAttributes) .setAcceptsDelayedFocusGain(true) .setOnAudioFocusChangeListener(afChangeListener, handler) .build(); final Object focusLock = new Object(); boolean playbackDelayed = false; boolean playbackNowAuthorized = false; // requesting audio focus and processing the response int res = audioManager.requestAudioFocus(focusRequest); synchronized(focusLock) { if (res == AudioManager.AUDIOFOCUS_REQUEST_FAILED) { playbackNowAuthorized = false; } else if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { playbackNowAuthorized = true; playbackNow(); } else if (res == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) { playbackDelayed = true; playbackNowAuthorized = false; } } // implementing OnAudioFocusChangeListener to react to focus changes @Override public void onAudioFocusChange(int focusChange) { switch (focusChange) { case AudioManager.AUDIOFOCUS_GAIN: if (playbackDelayed || resumeOnFocusGain) { synchronized(focusLock) { playbackDelayed = false; resumeOnFocusGain = false; } playbackNow(); } break; case AudioManager.AUDIOFOCUS_LOSS: synchronized(focusLock) { resumeOnFocusGain = false; playbackDelayed = false; } pausePlayback(); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: synchronized(focusLock) { // only resume if playback is being interrupted resumeOnFocusGain = isPlaying(); playbackDelayed = false; } pausePlayback(); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // ... pausing or ducking depends on your app break; } } }
Automatyczne wyciszanie
W Androidzie 8.0 (poziom interfejsu API 26), gdy inna aplikacja zażąda fokusu za pomocą AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
, system może przyciszyć i przywrócić głośność bez wywoływania wywołania zwrotnego onAudioFocusChange()
aplikacji.
Automatyczne ściszanie jest akceptowalnym zachowaniem w przypadku aplikacji do odtwarzania muzyki i filmów, ale nie jest przydatne podczas odtwarzania treści mówionych, np. w aplikacji do odtwarzania audiobooków. W takim przypadku aplikacja powinna wstrzymać odtwarzanie.
Jeśli chcesz, aby aplikacja wstrzymywała odtwarzanie, gdy zostanie poproszona o przyciszenie dźwięku, zamiast zmniejszać głośność, utwórz OnAudioFocusChangeListener
z metodą wywołania zwrotnego onAudioFocusChange()
, która implementuje żądane zachowanie wstrzymywania i wznawiania.
Zadzwoń pod numer setOnAudioFocusChangeListener()
, aby zarejestrować słuchacza, a następnie zadzwoń pod numer setWillPauseWhenDucked(true)
, aby poinformować system, że ma użyć Twojego wywołania zwrotnego zamiast automatycznego wyciszania.
Opóźnione uzyskanie ostrości
Czasami system nie może przyznać żądania fokusu audio, ponieważ jest on „zablokowany” przez inną aplikację, np. podczas rozmowy telefonicznej. W tym przypadku funkcja requestAudioFocus()
zwraca wartość AUDIOFOCUS_REQUEST_FAILED
. W takiej sytuacji aplikacja nie powinna odtwarzać dźwięku, ponieważ nie uzyskała fokusu.
Metoda setAcceptsDelayedFocusGain(true)
, która umożliwia aplikacji asynchroniczne obsługiwanie żądania fokusu. Gdy ta flaga jest ustawiona, żądanie wysłane, gdy fokus jest zablokowany, zwraca wartość AUDIOFOCUS_REQUEST_DELAYED
. Gdy warunek, który zablokował fokus audio, przestanie istnieć (np. po zakończeniu połączenia telefonicznego), system przyzna oczekującą prośbę o fokus i wywoła funkcję onAudioFocusChange()
, aby powiadomić aplikację.
Aby poradzić sobie z opóźnionym uzyskaniem fokusu, musisz utworzyć OnAudioFocusChangeListener
z metodą wywołania zwrotnego onAudioFocusChange()
, która implementuje żądane działanie, i zarejestrować odbiornik, wywołując setOnAudioFocusChangeListener()
.
Aktywność audio w Androidzie 7.1 i starszych
Gdy wywołujesz
requestAudioFocus()
musisz podać wskazówkę dotyczącą czasu trwania, która może
zostać uwzględniona przez inną aplikację, która jest obecnie aktywna i odtwarza:
- Poproś o stałe skupienie dźwięku (
AUDIOFOCUS_GAIN
), jeśli planujesz odtwarzać dźwięk w najbliższej przyszłości (np. podczas odtwarzania muzyki) i oczekujesz, że poprzedni posiadacz skupienia dźwięku przestanie odtwarzać. - Poproś o przejściowe skupienie (
AUDIOFOCUS_GAIN_TRANSIENT
), gdy chcesz odtwarzać dźwięk tylko przez krótki czas i oczekujesz, że poprzedni odtwarzacz wstrzyma odtwarzanie. - Poproś o przejściowe skupienie z wyciszeniem (
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
), aby wskazać, że zamierzasz odtwarzać dźwięk tylko przez krótki czas i że poprzedni właściciel skupienia może kontynuować odtwarzanie, jeśli „wyciszy” (obniży) poziom dźwięku. Oba wyjścia audio są miksowane w strumieniu audio. Ściszanie jest szczególnie przydatne w przypadku aplikacji, które korzystają ze strumienia audio z przerwami, np. w przypadku wskazówek dojazdu.
Metoda requestAudioFocus()
wymaga też AudioManager.OnAudioFocusChangeListener
. Ten odbiornik powinien być utworzony w tej samej aktywności lub usłudze, która jest właścicielem sesji multimedialnej. Implementuje wywołanie zwrotne onAudioFocusChange()
, które aplikacja otrzymuje, gdy inna aplikacja uzyska lub utraci fokus audio.
Poniższy fragment kodu wysyła prośbę o stałe skupienie dźwięku na strumieniu
STREAM_MUSIC
i rejestruje OnAudioFocusChangeListener
do obsługi
kolejnych zmian w skupieniu dźwięku. (O obserwatorze zmian piszemy w sekcji Reagowanie na zmianę fokusu dźwięku).
Kotlin
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager lateinit var afChangeListener AudioManager.OnAudioFocusChangeListener ... // Request audio focus for playback val result: Int = audioManager.requestAudioFocus( afChangeListener, // Use the music stream. AudioManager.STREAM_MUSIC, // Request permanent focus. AudioManager.AUDIOFOCUS_GAIN ) if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { // Start playback }
Java
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); AudioManager.OnAudioFocusChangeListener afChangeListener; ... // Request audio focus for playback int result = audioManager.requestAudioFocus(afChangeListener, // Use the music stream. AudioManager.STREAM_MUSIC, // Request permanent focus. AudioManager.AUDIOFOCUS_GAIN); if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { // Start playback }
Po zakończeniu odtwarzania kliknij Zadzwoń abandonAudioFocus()
.
Kotlin
audioManager.abandonAudioFocus(afChangeListener)
Java
// Abandon audio focus when playback complete audioManager.abandonAudioFocus(afChangeListener);
Informuje to system, że nie potrzebujesz już skupienia, i wyrejestrowuje powiązany OnAudioFocusChangeListener
. Jeśli zażądasz tymczasowego skupienia, powiadomisz aplikację, która została wstrzymana lub wyciszona, że może kontynuować odtwarzanie lub przywrócić głośność.
Reagowanie na zmianę fokusu dźwięku
Gdy aplikacja uzyska fokus audio, musi być w stanie go zwolnić, gdy inna aplikacja poprosi o fokus audio dla siebie. W takiej sytuacji aplikacja odbiera wywołanie metody onAudioFocusChange()
w AudioFocusChangeListener
, która została określona, gdy aplikacja wywołała requestAudioFocus()
.
Parametr focusChange
przekazywany do onAudioFocusChange()
wskazuje rodzaj
wprowadzanej zmiany. Odpowiada to wskazówce dotyczącej czasu trwania używanej przez aplikację, która uzyskuje fokus. Aplikacja powinna odpowiednio reagować.
- Przejściowa utrata ostrości
-
Jeśli zmiana fokusu jest tymczasowa (
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
lubAUDIOFOCUS_LOSS_TRANSIENT
), aplikacja powinna wyciszyć dźwięk (jeśli nie korzystasz z automatycznego wyciszania) lub wstrzymać odtwarzanie, ale w innych przypadkach zachować ten sam stan.Podczas przejściowej utraty aktywności audio należy nadal monitorować zmiany aktywności audio i być gotowym do wznowienia normalnego odtwarzania po odzyskaniu aktywności. Gdy aplikacja blokująca przestanie być aktywna, otrzymasz wywołanie zwrotne (
AUDIOFOCUS_GAIN
). W tym momencie możesz przywrócić normalny poziom głośności lub ponownie uruchomić odtwarzanie. - Trwała utrata ostrości
-
Jeśli utrata fokusu audio jest trwała (
AUDIOFOCUS_LOSS
), inna aplikacja odtwarza dźwięk. Aplikacja powinna natychmiast wstrzymać odtwarzanie, ponieważ nigdy nie otrzyma wywołania zwrotnegoAUDIOFOCUS_GAIN
. Aby ponownie uruchomić odtwarzanie, użytkownik musi wykonać wyraźną czynność, np. nacisnąć przycisk odtwarzania w powiadomieniu lub interfejsie aplikacji.
Poniższy fragment kodu pokazuje, jak wdrożyć funkcję OnAudioFocusChangeListener
i jej wywołanie zwrotne onAudioFocusChange()
. Zwróć uwagę na użycie Handler
, aby opóźnić wywołanie zwrotne zatrzymania w przypadku trwałej utraty fokusu audio.
Kotlin
private val handler = Handler() private val afChangeListener = AudioManager.OnAudioFocusChangeListener { focusChange -> when (focusChange) { AudioManager.AUDIOFOCUS_LOSS -> { // Permanent loss of audio focus // Pause playback immediately mediaController.transportControls.pause() // Wait 30 seconds before stopping playback handler.postDelayed(delayedStopRunnable, TimeUnit.SECONDS.toMillis(30)) } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { // Pause playback } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { // Lower the volume, keep playing } AudioManager.AUDIOFOCUS_GAIN -> { // Your app has been granted audio focus again // Raise volume to normal, restart playback if necessary } } }
Java
private Handler handler = new Handler(); AudioManager.OnAudioFocusChangeListener afChangeListener = new AudioManager.OnAudioFocusChangeListener() { public void onAudioFocusChange(int focusChange) { if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { // Permanent loss of audio focus // Pause playback immediately mediaController.getTransportControls().pause(); // Wait 30 seconds before stopping playback handler.postDelayed(delayedStopRunnable, TimeUnit.SECONDS.toMillis(30)); } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) { // Pause playback } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { // Lower the volume, keep playing } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { // Your app has been granted audio focus again // Raise volume to normal, restart playback if necessary } } };
Obsługa używa Runnable
, która wygląda tak:
Kotlin
private var delayedStopRunnable = Runnable { mediaController.transportControls.stop() }
Java
private Runnable delayedStopRunnable = new Runnable() { @Override public void run() { getMediaController().getTransportControls().stop(); } };
Aby mieć pewność, że opóźnione zatrzymanie nie zostanie uruchomione, jeśli użytkownik ponownie uruchomi odtwarzanie, wywołaj funkcję
mHandler.removeCallbacks(mDelayedStopRunnable)
w odpowiedzi na wszelkie zmiany stanu. Na przykład wywołaj removeCallbacks()
w funkcji wywołania zwrotnego onPlay()
, onSkipToNext()
itp. Tę metodę należy też wywołać w funkcji wywołania zwrotnego usługi onDestroy()
podczas czyszczenia zasobów używanych przez usługę.