Gestire la messa a fuoco audio

Due o più app per Android possono riprodurre audio nello stesso stream di output in contemporanea e il sistema mescola tutto insieme. Anche se impressionante dal punto di vista tecnico, può essere molto aggravante per un utente. Per evitare ogni di musica in esecuzione contemporaneamente, Android introduce l'idea di al focus. Solo un'app può mantenere lo stato attivo dell'audio alla volta.

Quando la tua app deve produrre audio, deve richiedere la messa a fuoco audio. Quando ha a fuoco, può riprodurre suoni. Tuttavia, una volta acquisito il focus audio, potresti non essere in grado di tenerlo attivo fino a quando non finisci di giocare. Un'altra app può richiedere lo stato attivo, prerilascia il blocco sul focus audio. In questo caso, l'app dovrebbe essere messa in pausa o abbassarne il volume per consentire agli utenti di sentire più facilmente la nuova sorgente audio.

Prima di Android 12 (livello API 31), il focus audio non è gestito dal sistema. Quindi, mentre gli sviluppatori di app sono invitati a rispettare le linee guida relative agli audio, se un'app continua a riprodurre ad alto volume anche dopo aver perso l'audio su un dispositivo con Android 11 (livello API 30) o versioni precedenti, il sistema non può evitarlo. Tuttavia, questo comportamento dell'app determina un'esperienza utente negativa e spesso può comportare di disinstallare l'app che funziona in modo anomalo.

Un'app audio ben progettata dovrebbe gestire il focus audio in base a queste caratteristiche generali linee guida:

  • Chiama requestAudioFocus() subito prima di iniziare a giocare e verifica che la chiamata restituisce AUDIOFOCUS_REQUEST_GRANTED Fai la chiamata a requestAudioFocus() nel callback onPlay() della sessione multimediale.

  • Quando un'altra app acquisisce la priorità dell'audio, interrompe o mette in pausa la riproduzione o riduce abbassare) il volume.

  • Quando la riproduzione si interrompe (ad esempio, quando nell'app non c'è più spazio da riprodurre), per abbandonare l'audio attivo. La tua app non deve abbandonare lo stato attivo dell'audio se l'utente mette in pausa la riproduzione, ma potrebbe riprendere la riproduzione in un secondo momento.

  • Utilizza AudioAttributes per descrivere il tipo di audio riprodotto dall'app. Ad esempio, per le app che riproducono il parlato, specificare CONTENT_TYPE_SPEECH

Lo stato attivo dell'audio viene gestito in modo diverso a seconda della versione di Android che è in esecuzione:

Android 12 (livello API 31) o versioni successive
Il focus dell'audio è gestito dal sistema. Il sistema forza la riproduzione audio da un un'app in dissolvenza quando un'altra app richiede il focus audio. Il sistema disattiva anche la riproduzione audio quando ricevi una chiamata.
Da Android 8.0 (livello API 26) ad Android 11 (livello API 30)
Il focus audio non è gestito dal sistema, ma include alcune modifiche che sono state introdotta 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 gestiscono la messa a fuoco audio utilizzando il requestAudioFocus() e abandonAudioFocus().

Focus audio in Android 12 e versioni successive

Un'app di giochi o contenuti multimediali che utilizza l'audio attivo non dovrebbe riprodurre audio dopo aver perso il focus. In Android 12 (livello API 31) e versioni successive, il sistema applica questa comportamento degli utenti. Quando un'app richiede lo stato attivo per l'audio mentre un'altra app ne ha è in riproduzione, il sistema forza la dissolvenza dell'app in riproduzione. L'aggiunta della classe la dissolvenza in uscita garantisce una transizione più fluida da un'app all'altra.

Questo comportamento di dissolvenza in uscita si verifica quando vengono soddisfatte le seguenti condizioni:

  1. La prima app attualmente in riproduzione soddisfa tutti i seguenti criteri:

  2. Una seconda app richiede il focus audio con AudioManager.AUDIOFOCUS_GAIN.

Quando queste condizioni sono soddisfatte, la prima app del sistema audio viene disattivata. Al alla fine della dissolvenza in uscita, il sistema avvisa la prima app della perdita di messa a fuoco. L'app l'audio dei lettori rimane disattivato finché l'app non richiede di nuovo lo stato attivo dell'audio.

Comportamenti esistenti del focus audio

Dovresti inoltre essere a conoscenza di questi altri casi che prevedono un cambio audio il focus.

Attenuazione automatica automatica

Attenuazione automatica automatica (riduzione temporanea del livello audio di un'app per un'altra si può sentire chiaramente) è stata introdotta in Android 8.0 (livello API 26).

Poiché il sistema implementa il attenuazione automatica, non sarà necessario implementarla la tua app.

Attenuazione automatica automatica si verifica anche quando una notifica audio raggiunge l'obiettivo da un'app di riproduzione. L'inizio della riproduzione della notifica è sincronizzato con la fine della rampa per abbattersi.

Attenuazione automatica automatica si verifica quando si verificano le seguenti condizioni:

  1. La prima app attualmente in riproduzione soddisfa tutti i seguenti criteri:

  2. Una seconda app richiede il focus audio con AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK

Quando queste condizioni sono soddisfatte, il sistema audio abbassa tutti i player attivi di la prima app, mentre la seconda con lo stato attivo. Quando la seconda app abbandona il focus, li rimuove. La prima app non riceve una notifica quando perde lo stato attivo. in modo che non debba fare nulla.

Tieni presente che l'attenuazione automatica non viene eseguita quando l'utente ascolta contenuti vocali, perché l'utente potrebbe perdere parte del programma. Ad esempio: la guida vocale per le indicazioni stradali non è oscurata.

Disattiva la riproduzione audio corrente per le telefonate in arrivo

Alcune app non funzionano correttamente e continuano a riprodurre l'audio durante le telefonate. Questa situazione costringe l'utente a trovare l'app in questione e a disattivarne l'audio o a chiuderla per ascoltare la loro chiamata. Per evitarlo, il sistema può disattivare l'audio di altri app durante una chiamata in arrivo. Il sistema richiama questa funzione quando quando si riceve una telefonata e un'app soddisfa le seguenti condizioni:

  • L'app include l'AudioAttributes.USAGE_MEDIA o Attributo di utilizzo AudioAttributes.USAGE_GAME.
  • L'app ha richiesto la messa a fuoco audio (qualsiasi guadagno) e la riproduzione è in corso audio.

Se la riproduzione di un'app continua durante la chiamata, la riproduzione viene disattivata fino a quando termina la chiamata. Tuttavia, se la riproduzione di un'app si avvia durante la chiamata, il player non viene disattivato, supponendo che l'utente abbia avviato intenzionalmente la riproduzione.

Focus audio da Android 8.0 ad Android 11

A partire da Android 8.0 (livello API 26), quando chiami requestAudioFocus() devi fornire un parametro AudioFocusRequest. AudioFocusRequest Contiene informazioni sul contesto audio e sulle funzionalità della tua app. La sistema utilizza queste informazioni per gestire il guadagno e la perdita dell'audio automaticamente. Per rilasciare lo stato attivo dell'audio, chiama il metodo abandonAudioFocusRequest() che accetta anche AudioFocusRequest come argomento. Usa lo stesso AudioFocusRequest sia quando richiedi che abbandoni lo stato attivo.

Per creare una AudioFocusRequest, usa un AudioFocusRequest.Builder. Poiché una richiesta di messa a fuoco deve specificare sempre il tipo di richiesta, il tipo è incluso nel costruttore per lo strumento di creazione. Utilizza i metodi del builder per impostare gli altri campi del richiesta.

Il campo FocusGain è obbligatorio. tutti gli altri campi sono facoltativi.

MetodoNote
setFocusGain() Questo campo è obbligatorio in tutte le richieste. Prende gli stessi valori di durationHint usato 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. La di sistema li esamina quando un'app acquisisce e perde la messa a fuoco audio. Attributi prevalgono sulla nozione di tipo di flusso. In Android 8.0 (livello API 26) e versioni successive, i tipi di flussi per qualsiasi operazione diversa dai controlli del volume sono deprecati. Utilizza le funzionalità di gli stessi attributi nella richiesta di impostazione dello stato attivo che utilizzi nel tuo lettore audio (ad esempio, mostrato nell'esempio che segue questa tabella).

Usa un AudioAttributes.Builder per specificare quindi utilizzare questo metodo per assegnare gli attributi richiesta.

Se non specificato, il valore predefinito di AudioAttributes è AudioAttributes.USAGE_MEDIA.

setWillPauseWhenDucked() Quando un'altra app richiede lo stato attivo AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, l'app su cui è attivo lo stato attivo non di solito ricevono un onAudioFocusChange() perché il sistema può eseguire si attenua da solo. Quando hai bisogno di mettere in pausa la riproduzione abbassa il volume, chiama setWillPauseWhenDucked(true), crea e imposta OnAudioFocusChangeListener, come descritto nella sezione automatica attenuazione automatica.
setAcceptsDelayedFocusGain() Una richiesta di messa a fuoco audio può non riuscire quando lo stato attivo è bloccato da un'altra app. Questo metodo consente il aumento della messa a fuoco ritardata, ovvero la capacità per acquisire l'attenzione in modo asincrono quando diventa disponibile.

Tieni presente che il guadagno dello stato attivo ritardato funziona solo se specifichi anche AudioManager.OnAudioFocusChangeListener nella richiesta audio, perché l'app deve ricevere il callback per sapere che lo stato attivo è stato concesso.

setOnAudioFocusChangeListener() Il campo 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 è l'argomento del gestore. Il gestore è il thread su cui viene eseguito il listener. Se non specificano un gestore, il gestore associato È in uso Looper.

L'esempio seguente mostra come utilizzare AudioFocusRequest.Builder per creare AudioFocusRequest e richiedere e abbandonare lo stato attivo dell'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 automatica

In Android 8.0 (livello API 26), quando un'altra app richiede lo stato attivo con AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK il sistema riesce a ridurre il volume e a ripristinare il volume senza richiamare il callback onAudioFocusChange() dell'app.

Sebbene l'attenuazione automatica automatica sia un comportamento accettabile per la riproduzione di musica e video app, non è utile durante la riproduzione di contenuti vocali, come in una app per audiolibri. In questo caso, l'app dovrebbe essere messa in pausa.

Se vuoi che la tua app venga messa in pausa quando ti viene chiesto di abbassare il volume anziché abbassarne il volume, crea un OnAudioFocusChangeListener con un metodo di callback onAudioFocusChange() che implementa il comportamento di pausa/ripresa desiderato. Chiama il numero setOnAudioFocusChangeListener() per registrare l'ascoltatore, quindi chiama setWillPauseWhenDucked(true) per indicare al sistema di utilizzare la richiamata anziché eseguire l'attenuazione automatica automatica.

Ritardo della messa a fuoco

A volte il sistema non può soddisfare una richiesta di messa a fuoco audio perché questo è "bloccato" da un'altra app, come durante una telefonata. In questo caso, requestAudioFocus() restituisce AUDIOFOCUS_REQUEST_FAILED. In questi casi, l'app non dovrebbe procedere con la riproduzione audio perché non ha il focus.

Il metodo setAcceptsDelayedFocusGain(true) che consente alla tua app di gestire una richiesta di impostazione dello stato attivo in modo asincrono. Con questo flag impostato, viene effettuata una richiesta quando lo stato attivo è bloccato restituisce AUDIOFOCUS_REQUEST_DELAYED. Quando la condizione che ha bloccato l'audio lo stato attivo non esiste più, ad esempio al termine di una telefonata, accetta la richiesta di messa a fuoco in attesa e chiama onAudioFocusChange() per inviare una notifica dell'app.

Per gestire il guadagno ritardato della messa a fuoco, devi creare un OnAudioFocusChangeListener con un metodo di callback onAudioFocusChange() che il comportamento desiderato e la registrazione del listener richiamando setOnAudioFocusChangeListener()

Focus audio in Android 7.1 e versioni precedenti

Quando chiami requestAudioFocus() devi specificare un suggerimento sulla durata, che può essere rispettata da un'altra app che attualmente mantiene lo stato attivo e in riproduzione:

  • Richiedi il focus audio permanente (AUDIOFOCUS_GAIN) quando prevedi di riprodurre l'audio per il prossimo futuro (ad esempio, durante la riproduzione di musica) e ti aspetti che precedente proprietario dell'audio attivo per interrompere la riproduzione.
  • Richiedi lo stato attivo temporaneo (AUDIOFOCUS_GAIN_TRANSIENT) quando prevedi di giocare solo per un breve periodo di tempo e ti aspetti che il titolare precedente venga messo in pausa che giocano.
  • Richiedi lo stato attivo temporaneo con la funzionalità di attenuazione automatica (AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) per indicare che prevedi di riprodurre l'audio per un breve periodo di tempo e che il precedente proprietario dell'elemento possa suona se "antra" (abbassa) l'output audio. Entrambe le uscite audio sono mixate nello stream audio. La funzionalità di attenuazione automatica è particolarmente adatta per le app che utilizzano audio a intermittenza, ad esempio per indicazioni stradali udibili.

Il metodo requestAudioFocus() richiede anche un elemento AudioManager.OnAudioFocusChangeListener. Questo listener dovrebbe essere creato nella stessa attività o nello stesso servizio proprietario della sessione multimediale. it implementa il callback onAudioFocusChange() che la tua app riceve quando alcune altre app acquisiscono o abbandonano il focus audio.

Il seguente snippet richiede un focus audio permanente sullo stream STREAM_MUSIC e registra un OnAudioFocusChangeListener da gestire le modifiche successive al focus audio. (Il listener delle modifiche viene discusso in Rispondere a un cambio di impostazione dell'elemento attivo su 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 informato che non hai più bisogno di messa a fuoco e viene annullata la registrazione del OnAudioFocusChangeListener associato. Se hai richiesto lo stato temporaneo, all'app che è stata messa in pausa o abbassata, verrà notificata la possibilità di continuare la riproduzione o ripristinare il suo volume.

Rispondere a un cambio di impostazione dello stato attivo per l'audio

Quando un'app acquisisce l'audio attivo, deve essere in grado di rilasciarlo quando un'altra app richiede la focalizzazione sull'audio. In questi casi, la tua app riceve una chiamata onAudioFocusChange() nel AudioFocusChangeListener specificato durante la chiamata dell'app requestAudioFocus().

Il parametro focusChange passato a onAudioFocusChange() indica il tipo di cambiamenti in atto. Corrisponde al suggerimento sulla durata utilizzato dall'app per cui è impostato lo stato attivo. La tua app dovrebbe di rispondere in modo appropriato.

Perdita di messa a fuoco temporanea
Se la modifica dell'elemento attivo è temporanea (AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK o AUDIOFOCUS_LOSS_TRANSIENT), la tua app dovrebbe ridursi (se non ti avvali sull'attenuazione automatica) o mettere in pausa la riproduzione, altrimenti manterranno lo stesso stato.

In caso di perdita temporanea dell'audio attivo, devi continuare a monitorare le modifiche con messa a fuoco audio e preparati a riprendere la riproduzione normale quando recuperi il 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 riavvia la riproduzione.

Perdita permanente dell'attenzione
Se la perdita dello stato attivo dell'audio è permanente (AUDIOFOCUS_LOSS), viene eseguita un'altra app la riproduzione di audio. La tua app dovrebbe mettere subito in pausa la riproduzione, poiché non sarà mai ricevi una richiamata di AUDIOFOCUS_GAIN. Per riavviare la riproduzione, l'utente deve eseguire un'azione esplicita, ad esempio premere il controllo di trasporto di Play in una notifica o nell'interfaccia utente dell'app.

Il seguente snippet di codice illustra come implementare il OnAudioFocusChangeListener e il relativo callback onAudioFocusChange(). Nota come utilizzo di Handler per ritardare la richiamata di interruzione in caso di perdita permanente dell'audio il focus.

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 stato modifiche. Ad esempio, chiama removeCallbacks() nel campo onPlay() del callback, onSkipToNext() e così via. Devi anche richiamare questo metodo nella onDestroy() durante la pulizia delle risorse utilizzate dal servizio.