2 lub więcej aplikacji na Androida może odtwarzać dźwięk na tym samym strumieniu wyjściowym jednocześnie, a system miksuje wszystko razem. Chociaż jest to technicznie imponujące, może to bardzo denerwować użytkownika. Aby uniknąć odtwarzania wszystkich aplikacji muzycznych jednocześnie, Android wprowadza funkcję fokusowania dźwięku. W danym momencie tylko jedna aplikacja może mieć dostęp do dźwięku.
Gdy aplikacja potrzebuje wyprowadzić dźwięk, powinna poprosić o skupienie na dźwięku. Gdy ma fokus, może odtwarzać dźwięk. Jednak po uzyskaniu kontroli nad dźwiękiem możesz nie mieć możliwości utrzymania jej do końca odtwarzania. Inna aplikacja może poprosić o utrzymanie fokusu, co zablokuje Twoje ustawienie. W takim przypadku aplikacja powinna wstrzymać odtwarzanie lub obniżyć głośność, aby użytkownicy mogli lepiej usłyszeć nowe źródło dźwięku.
Przed Androidem 12 (poziom interfejsu API 31) system nie zarządzał skupieniem na dźwięku. Deweloperzy aplikacji są zachęcani do przestrzegania wytycznych dotyczących dźwięku w tle, ale jeśli aplikacja nadal odtwarza dźwięk nawet po utracie dźwięku w tle na urządzeniu z Androidem 11 (poziom interfejsu API 30) lub starszym, system nie może temu zapobiec. Takie działanie aplikacji obniża jednak komfort użytkowników i często powoduje, że odinstalowują oni aplikację.
Dobrze zaprojektowana aplikacja do odtwarzania dźwięku powinna zarządzać skupieniem dźwięku zgodnie z tymi ogólnymi wskazówkami:
Zadzwoń pod numer
requestAudioFocus()
tuż przed rozpoczęciem gry i sprawdź, czy połączenie zostanie odebrane.AUDIOFOCUS_REQUEST_GRANTED
Wykonaj połączenie dorequestAudioFocus()
w ramach wywołania zwrotnegoonPlay()
sesji multimediów.Gdy inna aplikacja przejmuje dźwięk, zatrzymaj odtwarzanie lub wstrzymaj odtwarzanie, albo zmniejsz głośność.
Gdy odtwarzanie zostanie zatrzymane (np. gdy aplikacja nie ma już nic do odtworzenia), zatrzymaj tryb dźwięku w tle. Aplikacja nie musi tracić fokusu na dźwięku, jeśli użytkownik wstrzyma odtwarzanie, ale może wznowić odtwarzanie później.
Użyj atrybutu
AudioAttributes
, aby opisać typ odtwarzanego dźwięku w aplikacji. Na przykład w przypadku aplikacji odtwarzających mowę wpisz:CONTENT_TYPE_SPEECH
.
Tryb skupienia dźwięku jest obsługiwany inaczej w zależności od wersji Androida:
- Android 12 (poziom 31 interfejsu API) lub nowszy
- Tryb dźwięku jest zarządzany przez system. System powoduje, że odtwarzanie dźwięku z aplikacji zostaje wyciszone, gdy inna aplikacja prosi o uaktywnienie dźwięku. System wycisza też odtwarzanie dźwięku podczas połączenia przychodzącego.
- Android 8.0 (poziom 26 interfejsu API) do Androida 11 (poziom 30 interfejsu API)
- System nie zarządza dźwiękiem w tle, ale zawiera pewne zmiany wprowadzone w Androidzie 8.0 (poziom interfejsu API 26).
- Android 7.1 (poziom interfejsu API 25) lub starszy
- System nie zarządza dźwiękiem w tle, a aplikacje zarządzają dźwiękiem w tle za pomocą funkcji
requestAudioFocus()
iabandonAudioFocus()
.
Tryb skupienia na dźwięku w Androidzie 12 i nowszych
Aplikacja do multimediów lub gra, która korzysta z fokusa dźwięku, nie powinna odtwarzać dźwięku po utracie fokusu. W Androidzie 12 (poziom interfejsu API 31) i nowszym system wymusza takie działanie. Gdy aplikacja prosi o skupienie się na dźwięku, gdy inna aplikacja jest aktywna i odtwarza dźwięk, system powoduje zniknięcie dźwięku z innej aplikacji. Dodanie efektu znikania zapewnia płynniejsze przejście z jednej aplikacji do drugiej.
To zachowanie występuje, gdy są spełnione te warunki:
Pierwsza, aktualnie odtwarzana aplikacja spełnia wszystkie te kryteria:
- Aplikacja ma atrybut użytkowania
AudioAttributes.USAGE_MEDIA
lubAudioAttributes.USAGE_GAME
. - Aplikacja wysłała żądanie skupienia na dźwięku z
AudioManager.AUDIOFOCUS_GAIN
. - Aplikacja nie odtwarza dźwięku z typem treści
AudioAttributes.CONTENT_TYPE_SPEECH
.
- Aplikacja ma atrybut użytkowania
Druga aplikacja prosi o aktywność audio z użyciem
AudioManager.AUDIOFOCUS_GAIN
.
Gdy te warunki są spełnione, system audio powoduje wygładzenie dźwięku w pierwszej aplikacji. Po zakończeniu wygładzania system informuje pierwszą aplikację o utracie fokusu. Odtwarzacze aplikacji pozostają wyciszone, dopóki aplikacja ponownie nie poprosi o uprawnienia.
Dotychczasowe zachowania dotyczące priorytetu dźwięku
Musisz też pamiętać o tych innych przypadkach, które wiążą się ze zmianą punktu skupienia dźwięku.
Automatyczne wyciszanie
Automatyczne wyciszanie (tymczasowe zmniejszenie poziomu głośności jednej aplikacji, aby wyraźnie słyszeć inną) zostało wprowadzone w Androidzie 8.0 (poziom interfejsu API 26).
Jeśli system obsługuje wyciszanie, nie musisz go implementować w aplikacji.
Automatyczne stłumienie występuje też wtedy, gdy powiadomienie dźwiękowe przejmuje kontrolę nad odtwarzaniem z aplikacji. Początek odtwarzania powiadomienia jest zsynchronizowany z końcem rampy stłumienia.
Automatyczne wyciszanie następuje, gdy są spełnione te warunki:
Pierwsza, aktualnie odtwarzana aplikacja spełnia wszystkie te kryteria:
- Aplikacja poprosiła o ustawienie skupienia dźwięku z dowolnym typem focus gain.
- Aplikacja nie odtwarza dźwięku w przypadku typu treści
AudioAttributes.CONTENT_TYPE_SPEECH
. - Aplikacja nie ustawiła
AudioFocusRequest.Builder.setWillPauseWhenDucked(true)
.
Druga aplikacja prosi o uprawnienia dotyczące dźwięku:
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
.
Gdy te warunki są spełnione, system audio wycisza wszystkich aktywnych odtwarzaczy w pierwszej aplikacji, gdy druga aplikacja ma fokus. Gdy druga aplikacja przestaje być w centrum uwagi, powoduje to odblokowanie tych elementów. Pierwsza aplikacja nie jest powiadamiana, gdy traci na chwilę fokus, więc nie musi nic robić.
Pamiętaj, że automatyczne wyciszanie nie jest wykonywane, gdy użytkownik słucha treści mowy, ponieważ może on przegapić część programu. Na przykład wskazówki głosowe dotyczące wskazówek dojazdu nie są wyciszone.
wyciszyć bieżące odtwarzanie dźwięku podczas połączeń telefonicznych,
Niektóre aplikacje nie działają prawidłowo i nadal odtwarzają dźwięk podczas rozmów telefonicznych. W tej sytuacji użytkownik musi znaleźć i wyciszyć aplikację, która powoduje problem, lub ją zamknąć, aby móc usłyszeć połączenie. Aby temu zapobiec, system może wyciszyć dźwięk z innych aplikacji podczas połączenia przychodzącego. System uruchamia tę funkcję, gdy otrzymasz połączenie telefoniczne, a aplikacja spełnia te warunki:
- Aplikacja ma atrybut użycia
AudioAttributes.USAGE_MEDIA
lubAudioAttributes.USAGE_GAME
. - Aplikacja poprosiła o skupienie uwagi na dźwięku (dowolne skupienie uwagi) i odtwarza dźwięk.
Jeśli aplikacja nadal odtwarza dźwięk podczas rozmowy, zostanie wyciszona do jej zakończenia. Jeśli jednak podczas rozmowy włączy się odtwarzanie aplikacji, odtwarzacz nie zostanie wyciszony, ponieważ zakładamy, że użytkownik celowo rozpoczął odtwarzanie.
Koncentracja dźwięku w Androidzie 8.0–11
Począwszy od Androida 8.0 (poziom interfejsu API 26), podczas wywoływania funkcji requestAudioFocus()
musisz podać parametr AudioFocusRequest
. AudioFocusRequest
zawiera informacje o kontekście dźwięku i możliwościach aplikacji. System używa tych informacji do automatycznego zarządzania wzmocnieniem i utratą skupienia na dźwięku. Aby zwolnić aktywność audio, wywołaj metodę abandonAudioFocusRequest()
, która również przyjmuje argument AudioFocusRequest
. Używaj tej samej instancji AudioFocusRequest
zarówno podczas żądania, jak i opuszczania trybu pełnej koncentracji.
Aby utworzyć AudioFocusRequest
, użyj AudioFocusRequest.Builder
. Ponieważ żądanie fokusu musi zawsze określać typ żądania, typ jest uwzględniany w konstruktorze kreatora. Aby ustawić inne pola żądania, użyj metod konstruktora.
Pole FocusGain
jest wymagane, a pozostałe pola są opcjonalne.
Metoda | Uwagi |
---|---|
setFocusGain()
|
To pole jest wymagane w każdej prośbie. Przyjmuje te same wartości co durationHint używane w wywołaniu requestAudioFocus() w systemie Android 8.0: AUDIOFOCUS_GAIN , AUDIOFOCUS_GAIN_TRANSIENT , AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK lub AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE .
|
setAudioAttributes()
|
AudioAttributes określa przypadek użycia aplikacji. System sprawdza te wartości, gdy aplikacja zyskuje i traci nacisk dźwiękowy. Atrybuty zastępują pojęcie typu strumienia. W Androidzie w wersji 8.0 (poziom interfejsu API 26) i później typy strumienia dla operacji innych niż sterowanie głośnością są wycofane. Użyj w żądaniu fokusa tych samych atrybutów, których używasz w odtwarzaczu audio (jak pokazano w przykładzie po tej tabeli).
Najpierw użyj elementu
Jeśli nie podasz wartości parametru |
setWillPauseWhenDucked()
|
Gdy inna aplikacja poprosi o uzyskanie fokusu za pomocą wywołania AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK , aplikacja, która ma fokus, zwykle nie otrzymuje wywołania onAudioFocusChange() , ponieważ system może sam wykonać duckowanie. Jeśli chcesz wstrzymać odtwarzanie, a nie ściszyć głośności, wywołaj funkcję setWillPauseWhenDucked(true) i utwórz oraz ustaw funkcję OnAudioFocusChangeListener , jak opisano w sekcji Automatyczne ściszanie głośności.
|
setAcceptsDelayedFocusGain()
|
Prośba o uzyskanie kontroli nad dźwiękiem może się nie powieść, jeśli kontrolę tę ma inna aplikacja. Ta metoda umożliwia opóźnione przejęcie kontroli: asynchroniczne przejęcie kontroli, gdy tylko stanie się to możliwe.
Pamiętaj, że opóźnione wzmocnienie dźwięku działa tylko wtedy, gdy w prośbie o dostęp do mikrofonu podasz też parametr |
setOnAudioFocusChangeListener()
|
Właściwość OnAudioFocusChangeListener jest wymagana tylko wtedy, gdy w żądaniu określono też willPauseWhenDucked(true) lub setAcceptsDelayedFocusGain(true) .
Istnieją 2 metody ustawiania listenera: jedna z argumentem handlera, a druga bez niego. Obsługa to wątek, w którym działa odbiornik. Jeśli nie określisz uchwytu, zostanie użyty uchwyt powiązany z głównym |
Ten przykład pokazuje, jak użyć AudioFocusRequest.Builder
do utworzenia AudioFocusRequest
oraz jak poprosić o skupienie się na dźwięku i jego zaniechanie:
// 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 } } }
// 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 poprosi o skupienie uwagi za pomocą AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
, system może wyciszyć i przywrócić głośność bez wywoływania funkcji onAudioFocusChange()
aplikacji.
Automatyczne wyciszanie jest dopuszczalne w przypadku aplikacji do odtwarzania muzyki i filmów, ale nie jest przydatne podczas odtwarzania treści mówionej, np. w aplikacji z książkami audio. W takim przypadku aplikacja powinna się wstrzymać.
Jeśli chcesz, aby aplikacja wstrzymywała się, gdy poprosisz o ściszenie, zamiast zmniejszać głośność, utwórz OnAudioFocusChangeListener
z metodą wywołania onAudioFocusChange()
, która wdraża żądane zachowanie wstrzymywania i wznawiania.
Aby zarejestrować odbiorcę, wywołaj funkcję setOnAudioFocusChangeListener()
, a aby wskazać systemowi, że ma użyć wywołania zwrotnego zamiast automatycznego wyciszania, wywołaj funkcję setWillPauseWhenDucked(true)
.
Opóźnione wzmocnienie ostrości
Czasami system nie może spełnić prośby o skupienie się na dźwięku, ponieważ jest ono „zablokowane” przez inną aplikację, np. podczas rozmowy telefonicznej. W tym przypadku funkcja requestAudioFocus()
zwraca wartość AUDIOFOCUS_REQUEST_FAILED
. W takim przypadku aplikacja nie powinna odtwarzać dźwięku, ponieważ nie została skoncentrowana.
Metoda setAcceptsDelayedFocusGain(true)
, która umożliwia aplikacji asynchroniczne obsługiwanie żądania dotyczącego skupienia. Gdy ta flaga jest ustawiona, żądanie wysłane, gdy fokus jest zablokowany, zwraca wartość AUDIOFOCUS_REQUEST_DELAYED
. Gdy warunek, który zablokował dźwięk, przestanie obowiązywać, np. gdy połączenie telefoniczne się zakończy, system zaakceptuje oczekującą prośbę o włączenie trybu dźwiękowego i wywoła funkcję onAudioFocusChange()
, aby powiadomić Twoją aplikację.
Aby obsłużyć opóźnione uzyskanie fokusu, musisz utworzyć OnAudioFocusChangeListener
z metodą wywołania onAudioFocusChange()
, która implementuje pożądane działanie i rejestruje słuchacza, wywołując setOnAudioFocusChangeListener()
.
Aktywność audio w Androidzie 7.1 i starszych
Gdy wywołujesz elementrequestAudioFocus()
, musisz podać podpowiedź dotyczącą czasu trwania, która może być uwzględniona przez inną aplikację, która jest obecnie aktywna i odtwarzana:
- Poproś o trwałe skupienie na dźwięku (
AUDIOFOCUS_GAIN
), jeśli planujesz odtwarzać dźwięk przez dłuższy czas (np. podczas odtwarzania muzyki) i chcesz, aby poprzedni posiadacz skupienia na dźwięku zaprzestał odtwarzania. - Poproś o przejście w tryb przejściowy (
AUDIOFOCUS_GAIN_TRANSIENT
), gdy chcesz odtwarzać dźwięk tylko przez krótki czas i oczekujesz, że poprzedni właściciel wstrzyma odtwarzanie. - Żądanie przejściowego skupienia z podbiciem (
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
), aby wskazać, że dźwięk ma być odtwarzany tylko przez krótki czas i że poprzedni właściciel skupienia może nadal odtwarzać dźwięk, jeśli zmniejszy jego poziom. Oba wyjścia audio są miksowane w strumień audio. Ducking jest szczególnie przydatne w przypadku aplikacji, które od czasu do czasu używają strumienia audio, np. w przypadku wskazówek głosowych do nawigacji.
Metoda requestAudioFocus()
wymaga też AudioManager.OnAudioFocusChangeListener
. Ten odbiornik powinien zostać utworzony w tej samej aktywności lub usłudze, która jest właścicielem sesji multimedialnej. Implementuje ona funkcję wywołania zwrotnego onAudioFocusChange()
, którą Twoja aplikacja otrzymuje, gdy inna aplikacja uzyska lub straci skupienie na dźwięku.
Ten fragment kodu prosi o stałe skupienie się na strumieniu STREAM_MUSIC
i rejestruje zdarzenie OnAudioFocusChangeListener
, aby obsługiwać kolejne zmiany w fokusie dźwięku. (omawiamy go w artykule Reagowanie na zmianę dźwięku).
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 }
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 zadzwoń pod numer abandonAudioFocus()
.
audioManager.abandonAudioFocus(afChangeListener)
// Abandon audio focus when playback complete audioManager.abandonAudioFocus(afChangeListener);
To powiadomi system, że nie potrzebujesz już fokusa, i odpisze powiązany z nim OnAudioFocusChangeListener
. Jeśli poprosisz o tymczasowe skupienie, aplikacja, która została wstrzymana lub wyciszona, otrzyma powiadomienie, że może wznowić odtwarzanie lub przywrócić głośność.
Odpowiadanie na zmianę ustawień dźwięku
Gdy aplikacja uzyska dostęp do dźwięku, musi mieć możliwość zrezygnowania z niego, gdy inna aplikacja poprosi o to. W takim przypadku aplikacja otrzymuje wywołanie metody onAudioFocusChange()
w pakiecie AudioFocusChangeListener
, który został określony podczas wywołania metody requestAudioFocus()
.
Parametr focusChange
przekazany do funkcji onAudioFocusChange()
wskazuje rodzaj wprowadzanej zmiany. Odpowiada on podpowiedzi dotyczącej czasu używanej przez aplikację, która przejmuje fokus. Aplikacja powinna odpowiednio reagować.
- Przejściowa utrata ostrości
- Jeśli zmiana punktu skupienia jest przejściowa (
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 pozostałych aspektach zachować ten sam stan.Podczas chwilowej utraty aktywności audio należy nadal monitorować zmiany w aktywności audio i być gotowym do wznowienia normalnego odtwarzania po jej przywróceniu. Gdy aplikacja blokująca przestanie być aktywna, otrzymasz wywołanie zwrotne (
AUDIOFOCUS_GAIN
). W tym momencie możesz przywrócić głośność do normalnego poziomu lub wznowić odtwarzanie. - Utrata ostrości
- Jeśli utrata fokusu dźwięku 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 wznowić odtwarzanie, użytkownik musi wykonać wyraźną czynność, np. nacisnąć przycisk odtwarzania w powiadomieniu lub interfejsie aplikacji.
Ten fragment kodu pokazuje, jak zaimplementować funkcję OnAudioFocusChangeListener
i jej wywołanie zwrotne onAudioFocusChange()
. Zwróć uwagę na użycie funkcji Handler
, aby opóźnić wywołanie zwrotne stop w przypadku trwałej utraty fokusu dźwiękowego.
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 } } }
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óry wygląda tak:
private var delayedStopRunnable = Runnable { mediaController.transportControls.stop() }
private Runnable delayedStopRunnable = new Runnable() { @Override public void run() { getMediaController().getTransportControls().stop(); } };
Aby opóźnione zatrzymanie nie zostało uruchomione, jeśli użytkownik ponownie uruchomi odtwarzanie, wywołaj funkcję mHandler.removeCallbacks(mDelayedStopRunnable)
w odpowiedzi na zmiany stanu. Na przykład wywołaj removeCallbacks()
w metodach onPlay()
, onSkipToNext()
itp. w wywołaniu zwrotnym. Należy też wywołać tę metodę w wywołaniu zwrotnym onDestroy()
usługi podczas czyszczenia zasobów używanych przez usługę.