Due o più app per Android possono riprodurre audio nello stesso flusso di output contemporaneamente e il sistema mixa tutto. Sebbene sia tecnicamente impressionante, può essere molto irritante per un utente. Per evitare che tutte le app di musica vengano riprodotte contemporaneamente, Android introduce il concetto di messa a fuoco dell'audio. Solo un'app può mantenere il focus audio alla volta.
Quando la tua app deve riprodurre l'audio, deve richiedere la messa a fuoco audio. Quando è in primo piano, può riprodurre suoni. Tuttavia, dopo aver acquisito lo stato attivo dell'audio, potresti non essere in grado di mantenerlo fino al termine della riproduzione. Un'altra app può richiedere la messa a fuoco, che precede la tua presa sulla messa a fuoco audio. In questo caso, l'app deve mettere in pausa la riproduzione o abbassare il volume per consentire agli utenti di ascoltare più facilmente la nuova sorgente audio.
Prima di Android 12 (livello API 31), la messa a fuoco audio non è gestita dal sistema. Pertanto, anche se gli sviluppatori di app sono invitati a rispettare le linee guida per la gestione della messa a fuoco audio, se un'app continua a riprodurre audio ad alto volume anche dopo aver perso la messa a fuoco audio su un dispositivo con Android 11 (livello API 30) o versioni precedenti, il sistema non può impedirlo. Tuttavia, questo comportamento dell'app porta a un'esperienza utente negativa e spesso gli utenti a disinstallare l'app che non funziona correttamente.
Un'app audio ben progettata deve gestire la messa a fuoco audio in base a queste linee guida generali:
Chiama il numero
requestAudioFocus()
immediatamente prima di iniziare a giocare e verifica che la chiamata restituiscaAUDIOFOCUS_REQUEST_GRANTED
. ChiamarequestAudioFocus()
nel callbackonPlay()
della sessione multimediale.Quando un'altra app acquisisce la priorità audio, interrompi o metti in pausa la riproduzione oppure abbassa il volume.
Quando la riproduzione si interrompe (ad esempio, quando l'app non ha più nulla da riprodurre), abbandona la messa a fuoco audio. La tua app non deve abbandonare la messa a fuoco audio se l'utente mette in pausa la riproduzione, ma potrebbe riprenderla in un secondo momento.
Utilizza
AudioAttributes
per descrivere il tipo di audio riprodotto dalla tua app. Ad esempio, per le app che riproducono la voce, specificaCONTENT_TYPE_SPEECH
.
La gestione della messa a fuoco audio varia a seconda della versione di Android in esecuzione:
- Android 12 (livello API 31) o versioni successive
- La messa a fuoco dell'audio è gestita dal sistema. Il sistema forza la dissolvenza della riproduzione audio di un'app quando un'altra app richiede il focus audio. Il sistema disattiva anche la riproduzione audio quando viene ricevuta una chiamata in arrivo.
- Android 8.0 (livello API 26) fino ad Android 11 (livello API 30)
- La messa a fuoco audio non è gestita dal sistema, ma include alcune modifiche introdotte a partire da Android 8.0 (livello API 26).
- Android 7.1 (livello API 25) e versioni precedenti
- La messa a fuoco audio non è gestita dal sistema e le app la gestiscono utilizzando
requestAudioFocus()
eabandonAudioFocus()
.
Focus audio in Android 12 e versioni successive
Un'app multimediale o di gioco che utilizza l'audio focus non deve riprodurre audio dopo aver perso il focus. In Android 12 (livello API 31) e versioni successive, il sistema impone questo comportamento. Quando un'app richiede l'audio focus mentre un'altra app ha il focus e sta riproducendo contenuti, il sistema forza la dissolvenza in uscita dell'app in riproduzione. L'aggiunta della dissolvenza in uscita offre una transizione più fluida quando si passa da un'app all'altra.
Questo comportamento di dissolvenza si verifica quando sono soddisfatte le seguenti condizioni:
La prima app in riproduzione soddisfa tutti questi criteri:
- L'app ha l'attributo di utilizzo
AudioAttributes.USAGE_MEDIA
oAudioAttributes.USAGE_GAME
. - L'app ha richiesto correttamente la messa a fuoco dell'audio con
AudioManager.AUDIOFOCUS_GAIN
. - L'app non riproduce audio con il tipo di contenuti
AudioAttributes.CONTENT_TYPE_SPEECH
.
- L'app ha l'attributo di utilizzo
Una seconda app richiede il focus audio con
AudioManager.AUDIOFOCUS_GAIN
.
Quando queste condizioni sono soddisfatte, il sistema audio attenua l'audio della prima app. Al termine dell'attenuazione, il sistema notifica alla prima app la perdita dello stato attivo. I lettori dell'app rimangono disattivati finché l'app non richiede di nuovo il focus audio.
Comportamenti esistenti della messa a fuoco dell'audio
Devi anche tenere presente questi altri casi che comportano un cambio di messa a fuoco dell'audio.
Attenuazione automatica audio
L'attenuazione automatica (riduzione temporanea del livello audio di un'app in modo che un'altra possa essere ascoltata chiaramente) è stata introdotta in Android 8.0 (livello API 26).
Se il sistema implementa il ducking, non devi implementarlo nella tua app.
La riduzione automatica si verifica anche quando una notifica audio acquisisce lo stato attivo da un'app in riproduzione. L'inizio della riproduzione della notifica è sincronizzato con la fine della rampa di riduzione.
La riduzione automatica si verifica quando sono soddisfatte le seguenti condizioni:
La prima app in riproduzione soddisfa tutti questi criteri:
- L'app ha richiesto correttamente l'audio focus con qualsiasi tipo di acquisizione del focus.
- L'app non riproduce audio con il tipo di contenuti
AudioAttributes.CONTENT_TYPE_SPEECH
. - L'app non ha impostato
AudioFocusRequest.Builder.setWillPauseWhenDucked(true)
.
Una seconda app richiede l'audio con
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
.
Quando queste condizioni sono soddisfatte, il sistema audio abbassa il volume di tutti i player attivi della prima app mentre la seconda app è in primo piano. Quando la seconda app perde il focus, viene sganciata. La prima app non riceve una notifica quando perde lo stato attivo, quindi non deve fare nulla.
Tieni presente che la riduzione automatica non viene eseguita quando l'utente ascolta contenuti vocali, perché potrebbe perdere parte del programma. Ad esempio, le indicazioni vocali per le indicazioni stradali non vengono attenuate.
Disattivare la riproduzione audio corrente per le chiamate in arrivo
Alcune app non funzionano correttamente e continuano a riprodurre audio durante le chiamate. Questa situazione costringe l'utente a trovare e disattivare l'audio o chiudere l'app incriminata per sentire la chiamata. Per evitare questo problema, il sistema può disattivare l'audio di altre app quando c'è una chiamata in arrivo. Il sistema richiama questa funzionalità quando viene ricevuta una chiamata in arrivo e un'app soddisfa le seguenti condizioni:
- L'app ha l'attributo di utilizzo
AudioAttributes.USAGE_MEDIA
oAudioAttributes.USAGE_GAME
. - L'app ha richiesto correttamente l'audio focus (qualsiasi acquisizione del focus) e sta riproducendo audio.
Se un'app continua a essere riprodotta durante la chiamata, la riproduzione viene disattivata fino al termine della chiamata. Tuttavia, se un'app inizia la riproduzione durante la chiamata, il player non viene disattivato, in quanto si presume che l'utente abbia avviato la riproduzione intenzionalmente.
Focus audio in Android 8.0 - Android 11
A partire da Android 8.0 (livello API 26), quando chiami
requestAudioFocus()
devi fornire un parametro AudioFocusRequest
. AudioFocusRequest
contiene informazioni sul contesto e sulle funzionalità audio della tua app. Il
sistema utilizza queste informazioni per gestire automaticamente l'acquisizione e la perdita della messa a fuoco audio. Per rilasciare il focus audio, chiama il metodo
abandonAudioFocusRequest()
che accetta anche un AudioFocusRequest
come argomento. Utilizza la stessa istanza AudioFocusRequest
sia quando richiedi che quando abbandoni la messa a fuoco.
Per creare un AudioFocusRequest
, utilizza un
AudioFocusRequest.Builder
. Poiché una richiesta di messa a fuoco deve
sempre specificare il tipo di richiesta, il tipo è incluso nel costruttore
per il builder. Utilizza i metodi del builder per impostare gli altri campi della
richiesta.
Il campo FocusGain
è obbligatorio; tutti gli altri campi sono facoltativi.
Metodo | Note |
---|---|
setFocusGain()
|
Questo campo è obbligatorio in ogni richiesta. Assume gli stessi valori di
durationHint utilizzato nella chiamata precedente ad Android 8.0 a requestAudioFocus() :
AUDIOFOCUS_GAIN , AUDIOFOCUS_GAIN_TRANSIENT ,
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK o AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE .
|
setAudioAttributes()
|
AudioAttributes descrive il caso d'uso della tua app. Il
sistema li esamina quando un'app acquisisce e perde lo stato attivo audio. Gli attributi
sostituiscono la nozione di tipo di stream. In Android 8.0 (livello API 26) e versioni successive,
i tipi di stream per qualsiasi operazione diversa dai controlli del volume sono ritirati. Utilizza
gli stessi attributi nella richiesta di messa a fuoco che utilizzi nel tuo lettore audio (come
mostrato nell'esempio che segue questa tabella).
Utilizza un
Se non specificato, il valore predefinito di |
setWillPauseWhenDucked()
|
Quando un'altra app richiede il focus con
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK , l'app che ha il focus di solito non
riceve un
callback onAudioFocusChange()
perché il sistema può eseguire
la riduzione del volume da solo. Quando devi mettere in pausa la riproduzione anziché abbassare il volume, chiama setWillPauseWhenDucked(true) e crea e imposta un OnAudioFocusChangeListener , come descritto in Abbassamento automatico.
|
setAcceptsDelayedFocusGain()
|
Una richiesta di focus audio può non riuscire quando il focus è bloccato da un'altra app.
Questo metodo consente l'acquisizione ritardata del focus: la possibilità
di acquisire in modo asincrono il focus quando diventa disponibile.
Tieni presente che l'acquisizione ritardata del focus funziona solo se specifichi anche un
|
setOnAudioFocusChangeListener()
|
Un OnAudioFocusChangeListener è obbligatorio solo se specifichi anche
willPauseWhenDucked(true) o setAcceptsDelayedFocusGain(true) nella richiesta.
Esistono due metodi per impostare il listener: uno con e uno senza un
argomento del gestore. L'handler è il thread su cui viene eseguito il listener. Se non
specifichi un gestore, viene utilizzato quello associato al |
L'esempio seguente mostra come utilizzare un AudioFocusRequest.Builder
per creare un AudioFocusRequest
e richiedere e abbandonare la messa a fuoco audio:
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; } } }
Attenuazione automatica audio
In Android 8.0 (livello API 26), quando un'altra app richiede lo stato attivo con
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
il sistema può abbassare e ripristinare il volume
senza richiamare il callback onAudioFocusChange()
dell'app.
Sebbene la riduzione automatica sia un comportamento accettabile per le app di riproduzione di musica e video, non è utile quando si riproducono contenuti parlati, ad esempio in un'app di audiolibri. In questo caso, l'app deve mettere in pausa.
Se vuoi che la tua app si metta in pausa quando le viene chiesto di abbassare il volume anziché diminuirlo, crea un OnAudioFocusChangeListener
con
un metodo di callback onAudioFocusChange()
che implementi il comportamento di pausa/riproduzione desiderato.
Chiama il numero setOnAudioFocusChangeListener()
per registrare l'ascoltatore e chiama il numero
setWillPauseWhenDucked(true)
per indicare al sistema di utilizzare il richiamo anziché eseguire l'abbassamento automatico.
Acquisizione ritardata della messa a fuoco
A volte il sistema non può concedere una richiesta di focus audio perché il focus è
"bloccato" da un'altra app, ad esempio durante una telefonata. In questo caso,
requestAudioFocus()
restituisce AUDIOFOCUS_REQUEST_FAILED
. In questo caso,
la tua app non deve procedere con la riproduzione audio perché non ha acquisito
il focus.
Il metodo, setAcceptsDelayedFocusGain(true)
, che consente all'app di gestire una richiesta di messa a fuoco
in modo asincrono. Se questo flag è impostato, una richiesta effettuata quando la messa a fuoco è bloccata
restituisce AUDIOFOCUS_REQUEST_DELAYED
. Quando la condizione che ha bloccato
il focus audio non esiste più, ad esempio quando una chiamata termina, il sistema
concede la richiesta di focus in attesa e chiama onAudioFocusChange()
per notificare la tua
app.
Per gestire l'acquisizione ritardata dello stato attivo, devi creare un
OnAudioFocusChangeListener
con un metodo di callback onAudioFocusChange()
che
implementi il comportamento desiderato e registrare il listener chiamando
setOnAudioFocusChangeListener()
.
Focus audio in Android 7.1 e versioni precedenti
Quando chiami
requestAudioFocus()
devi specificare un suggerimento sulla durata, che potrebbe
essere rispettato da un'altra app attualmente in primo piano e in riproduzione:
- Richiedi la messa a fuoco audio permanente (
AUDIOFOCUS_GAIN
) quando prevedi di riprodurre audio per il futuro prevedibile (ad esempio, quando ascolti musica) e ti aspetti che il precedente titolare della messa a fuoco audio interrompa la riproduzione. - Richiedi la messa in primo piano temporanea (
AUDIOFOCUS_GAIN_TRANSIENT
) quando prevedi di riprodurre l'audio solo per un breve periodo di tempo e prevedi che il precedente titolare metta in pausa la riproduzione. - Richiedi la messa in primo piano temporanea con attenuazione
(
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
) per indicare che prevedi di riprodurre l'audio solo per un breve periodo di tempo e che il precedente proprietario della messa in primo piano può continuare la riproduzione se "attenua" (abbassa) l'output audio. Entrambi gli output audio vengono mixati nello stream audio. La riduzione è particolarmente adatta alle app che utilizzano il flusso audio in modo intermittente, ad esempio per le indicazioni stradali vocali.
Il metodo requestAudioFocus()
richiede anche un AudioManager.OnAudioFocusChangeListener
. Questo listener deve essere
creato nella stessa attività o servizio proprietario della sessione multimediale. Implementa il callback onAudioFocusChange()
che la tua app riceve quando
un'altra app acquisisce o abbandona l'audio focus.
Il seguente snippet richiede la messa a fuoco audio permanente sullo stream
STREAM_MUSIC
e registra un OnAudioFocusChangeListener
per gestire
le successive modifiche della messa a fuoco audio. Il listener di modifica è descritto in
Rispondere a una modifica dello stato di messa a fuoco audio.
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 }
Al termine della riproduzione, chiama
abandonAudioFocus()
.
Kotlin
audioManager.abandonAudioFocus(afChangeListener)
Java
// Abandon audio focus when playback complete audioManager.abandonAudioFocus(afChangeListener);
In questo modo, il sistema viene avvisato che non è più necessario mettere a fuoco e viene annullata la registrazione del
OnAudioFocusChangeListener
associato. Se hai richiesto la messa in primo piano temporanea,
un'app in pausa o che ha abbassato il volume riceverà una notifica che le comunica che può continuare la riproduzione o
ripristinare il volume.
Rispondere a una modifica della messa a fuoco audio
Quando un'app acquisisce lo stato attivo audio, deve essere in grado di rilasciarlo quando un'altra app
lo richiede per sé. In questo caso, la tua app
riceve una chiamata al
metodo onAudioFocusChange()
nell'AudioFocusChangeListener
che hai specificato quando l'app ha chiamato requestAudioFocus()
.
Il parametro focusChange
passato a onAudioFocusChange()
indica il tipo
di modifica in corso. Corrisponde
al suggerimento sulla durata utilizzato dall'app che acquisisce lo stato attivo. La tua app deve
rispondere in modo appropriato.
- Perdita temporanea della messa a fuoco
-
Se il cambio di messa a fuoco è temporaneo (
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
oAUDIOFOCUS_LOSS_TRANSIENT
), l'app deve abbassare il volume (se non si basa sull'abbassamento automatico) o mettere in pausa la riproduzione, ma mantenere lo stesso stato.Durante una perdita temporanea del focus audio, devi continuare a monitorare le modifiche del focus audio ed essere pronto a riprendere la normale riproduzione quando riacquisisci il focus. Quando l'app di blocco abbandona lo stato attivo, ricevi un callback (
AUDIOFOCUS_GAIN
). A questo punto, puoi ripristinare il volume al livello normale o riavviare la riproduzione. - Perdita permanente della messa a fuoco
-
Se la perdita di focus audio è permanente (
AUDIOFOCUS_LOSS
), un'altra app sta riproducendo audio. La riproduzione dell'app deve essere messa in pausa immediatamente, in quanto non riceverà mai un callbackAUDIOFOCUS_GAIN
. Per riavviare la riproduzione, l'utente deve eseguire un'azione esplicita, ad esempio premere il controllo di riproduzione in una notifica o nell'interfaccia utente dell'app.
Il seguente snippet di codice mostra come implementare
OnAudioFocusChangeListener
e il relativo callback onAudioFocusChange()
. Nota l'uso di un Handler
per ritardare il callback di interruzione in caso di perdita permanente della messa a fuoco 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 } } };
Il gestore utilizza un Runnable
simile al seguente:
Kotlin
private var delayedStopRunnable = Runnable { mediaController.transportControls.stop() }
Java
private Runnable delayedStopRunnable = new Runnable() { @Override public void run() { getMediaController().getTransportControls().stop(); } };
Per assicurarti che l'interruzione ritardata non venga attivata se l'utente riavvia la riproduzione, chiama
mHandler.removeCallbacks(mDelayedStopRunnable)
in risposta a qualsiasi modifica
dello stato. Ad esempio, chiama removeCallbacks()
nel callback onPlay()
,
onSkipToNext()
e così via. Devi chiamare questo metodo anche nel callback onDestroy()
del servizio durante la pulizia delle risorse utilizzate dal servizio.