Audiofokus verwalten

Zwei oder mehr Android-Apps können Audio gleichzeitig über denselben Ausgabestream abspielen und das System mischt alles zusammen. Das ist zwar technisch beeindruckend, kann aber für Nutzer sehr frustrierend sein. Damit nicht alle Musik-Apps gleichzeitig abgespielt werden, führt Android den Audiofokus ein. Der Audiofokus kann immer nur auf eine App festgelegt werden.

Wenn Ihre App Audio ausgeben muss, sollte sie den Audiofokus anfordern. Wenn der Fokus darauf liegt, kann er Ton wiedergeben. Nachdem Sie den Audiofokus erhalten haben, können Sie ihn möglicherweise nicht bis zum Ende der Wiedergabe beibehalten. Eine andere App kann den Fokus anfordern, wodurch Ihr Audiofokus aufgehoben wird. In diesem Fall sollte Ihre App die Wiedergabe pausieren oder die Lautstärke verringern, damit Nutzer die neue Audioquelle besser hören können.

Vor Android 12 (API-Level 31) wird der Audiofokus nicht vom System verwaltet. App-Entwickler werden zwar aufgefordert, die Richtlinien zum Audiofokus einzuhalten, aber wenn eine App auf einem Gerät mit Android 11 (API-Level 30) oder niedriger auch dann laut wiedergegeben wird, wenn der Audiofokus verloren geht, kann das System dies nicht verhindern. Dieses App-Verhalten führt jedoch zu einer schlechten Nutzererfahrung und kann dazu führen, dass Nutzer die fehlerhafte App deinstallieren.

In einer gut gestalteten Audio-App sollte der Audiofokus gemäß diesen allgemeinen Richtlinien verwaltet werden:

  • Rufe requestAudioFocus() an, bevor du mit dem Spiel beginnst, und prüfe, ob du die Rückrufnummer AUDIOFOCUS_REQUEST_GRANTED erhältst. Rufe requestAudioFocus() im onPlay()-Callback deiner Mediensitzung auf.

  • Wenn eine andere App den Audiofokus erhält, beenden oder pausieren Sie die Wiedergabe oder senken Sie die Lautstärke.

  • Wenn die Wiedergabe stoppt (z. B. wenn in der App nichts mehr zu wiedergeben ist), geben Sie den Audiofokus auf. Ihre App muss den Audiofokus nicht aufgeben, wenn der Nutzer die Wiedergabe pausiert, sondern kann die Wiedergabe später fortsetzen.

  • Verwenden Sie AudioAttributes, um die Art der Audioinhalte zu beschreiben, die in Ihrer App abgespielt werden. Geben Sie für Apps, die Sprache wiedergeben, beispielsweise CONTENT_TYPE_SPEECH an.

Der Audiofokus wird je nach installierter Android-Version unterschiedlich behandelt:

Android 12 (API-Level 31) oder höher
Der Audiofokus wird vom System verwaltet. Das System blendet die Audiowiedergabe einer App aus, wenn eine andere App den Audiofokus anfordert. Außerdem wird die Audiowiedergabe stummgeschaltet, wenn ein eingehender Anruf empfangen wird.
Android 8.0 (API-Level 26) bis Android 11 (API-Level 30)
Der Audiofokus wird nicht vom System verwaltet, umfasst aber einige Änderungen, die ab Android 8.0 (API-Ebene 26) eingeführt wurden.
Android 7.1 (API-Level 25) und niedriger
Der Audiofokus wird nicht vom System verwaltet. Apps verwalten den Audiofokus mit den Tasten requestAudioFocus() und abandonAudioFocus().

Audiofokus unter Android 12 und höher

Eine Medien- oder Spiele-App, die den Audiofokus verwendet, sollte keine Audioinhalte abspielen, wenn der Fokus verloren geht. Unter Android 12 (API-Level 31) und höher erzwingt das System dieses Verhalten. Wenn eine App den Audiofokus anfordert, während eine andere App den Fokus hat und gerade wiedergegeben wird, wird die Wiedergabe der App erzwungen. Durch das Hinzufügen des Ausblendens wird der Übergang von einer App zur nächsten flüssiger.

Dieses Ausblenden tritt auf, wenn die folgenden Bedingungen erfüllt sind:

  1. Die erste, derzeit wiedergegebene App erfüllt alle folgenden Kriterien:

  2. Eine zweite App fordert mit AudioManager.AUDIOFOCUS_GAIN den Audiofokus an.

Wenn diese Bedingungen erfüllt sind, blendet das Audiosystem die erste App aus. Am Ende des Ausblendens benachrichtigt das System die erste App über den Verlust des Fokus. Die Player der App bleiben stummgeschaltet, bis die App den Audiofokus wieder anfordert.

Vorhandene Audiofokus-Verhalten

Beachte auch die folgenden Fälle, in denen der Audiofokus wechselt.

Automatisches Ducking

Die automatische Stummschaltung (vorübergehendes Heruntersetzen der Lautstärke einer App, damit eine andere besser zu hören ist) wurde in Android 8.0 (API-Ebene 26) eingeführt.

Wenn das System die Funktion implementiert, müssen Sie sie nicht in Ihrer App implementieren.

Die automatische Stummschaltung erfolgt auch, wenn eine Audiobenachrichtigung den Fokus von einer wiedergegebenen App übernimmt. Der Beginn der Benachrichtigungswiedergabe wird mit dem Ende der Ducking-Rampe synchronisiert.

Die automatische Stummschaltung wird ausgelöst, wenn die folgenden Bedingungen erfüllt sind:

  1. Die erste, derzeit wiedergegebene App erfüllt alle folgenden Kriterien:

  2. Eine zweite App fordert den Audiofokus mit AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK an.

Wenn diese Bedingungen erfüllt sind, dämpft das Audiosystem alle aktiven Player der ersten App, während die zweite App den Fokus hat. Wenn die zweite App den Fokus verliert, werden sie wieder eingeblendet. Die erste App wird nicht benachrichtigt, wenn der Fokus darauf verloren geht, und muss daher nichts tun.

Hinweis: Die automatische Stummschaltung wird nicht ausgeführt, wenn der Nutzer sich Sprachinhalte anhört, da er sonst Teile des Programms verpassen könnte. Die Sprachnavigation für die Routenführung wird beispielsweise nicht gedimmt.

Aktuelle Audiowiedergabe bei eingehenden Anrufen stummschalten

Einige Apps funktionieren nicht richtig und geben während eines Anrufs weiterhin Audio wieder. In diesem Fall muss der Nutzer die betreffende App finden und stummschalten oder beenden, um den Anruf zu hören. Um dies zu verhindern, kann das System Audio von anderen Apps stummschalten, während ein Anruf eingeht. Das System ruft diese Funktion auf, wenn ein eingehender Anruf empfangen wird und eine App die folgenden Bedingungen erfüllt:

  • Die App hat entweder das Nutzungsattribut AudioAttributes.USAGE_MEDIA oder AudioAttributes.USAGE_GAME.
  • Die App hat den Audiofokus (beliebige Fokusgewinnung) angefordert und spielt Audio ab.

Wenn eine App während des Anrufs weiter abgespielt wird, wird die Wiedergabe stummgeschaltet, bis der Anruf beendet ist. Wenn jedoch während eines Anrufs eine App wiedergegeben wird, wird der Player nicht stummgeschaltet, da davon ausgegangen wird, dass der Nutzer die Wiedergabe absichtlich gestartet hat.

Audiofokus unter Android 8.0 bis Android 11

Ab Android 8.0 (API-Ebene 26) müssen Sie beim Aufruf von requestAudioFocus() einen AudioFocusRequest-Parameter angeben. Die AudioFocusRequest enthält Informationen zum Audiokontext und zu den Funktionen Ihrer App. Das System verwendet diese Informationen, um den Gewinn und Verlust des Audiofokus automatisch zu verwalten. Wenn Sie den Audiofokus aufheben möchten, rufen Sie die Methode abandonAudioFocusRequest() auf, die ebenfalls ein AudioFocusRequest als Argument erwartet. Verwenden Sie dieselbe AudioFocusRequest-Instanz, wenn Sie den Fokus anfordern und aufheben.

Verwenden Sie zum Erstellen einer AudioFocusRequest einen AudioFocusRequest.Builder. Da für eine Fokusanfrage immer der Anfragetyp angegeben werden muss, ist der Typ im Konstruktor für den Builder enthalten. Verwenden Sie die Methoden des Builders, um die anderen Felder der Anfrage festzulegen.

Das Feld FocusGain ist ein Pflichtfeld. Alle anderen Felder sind optional.

MethodHinweise
setFocusGain() Dieses Feld ist in jeder Anfrage erforderlich. Es werden dieselben Werte wie für durationHint verwendet, die vor Android 8.0 beim Aufruf von requestAudioFocus() verwendet wurden: AUDIOFOCUS_GAIN, AUDIOFOCUS_GAIN_TRANSIENT, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK oder AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE.
setAudioAttributes() AudioAttributes beschreibt den Anwendungsfall für Ihre App. Das System prüft, ob eine App den Audiofokus erhält oder verliert. Attribute ersetzen den Streamtyp. Ab Android 8.0 (API-Level 26) werden Streamtypen für alle Vorgänge außer der Lautstärkeregelung eingestellt. Verwende in der Fokusanfrage dieselben Attribute wie in deinem Audioplayer (siehe Beispiel nach dieser Tabelle).

Verwenden Sie zuerst ein AudioAttributes.Builder, um die Attribute anzugeben, und verwenden Sie dann diese Methode, um die Attribute der Anfrage zuzuweisen.

Wenn AudioAttributes nicht angegeben ist, wird standardmäßig AudioAttributes.USAGE_MEDIA verwendet.

setWillPauseWhenDucked() Wenn eine andere App den Fokus mit AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK anfordert, erhält die App, die den Fokus hat, in der Regel keinen onAudioFocusChange()-Callback, da das System das Ausblenden selbst vornehmen kann. Wenn du die Wiedergabe pausieren und nicht die Lautstärke senken möchtest, ruf setWillPauseWhenDucked(true) auf und erstelle und lege eine OnAudioFocusChangeListener fest, wie unter automatische Stummschaltung beschrieben.
setAcceptsDelayedFocusGain() Eine Anfrage für den Audiofokus kann fehlschlagen, wenn der Fokus von einer anderen App gesperrt ist. Mit dieser Methode ist die verzögerte Fokusgewinnung möglich: Der Fokus kann asynchron erworben werden, sobald er verfügbar ist.

Die verzögerte Fokusgewinnung funktioniert nur, wenn Sie in der Audioanfrage auch eine AudioManager.OnAudioFocusChangeListener angeben, da Ihre App den Rückruf erhalten muss, um zu wissen, dass der Fokus gewährt wurde.

setOnAudioFocusChangeListener() Ein OnAudioFocusChangeListener ist nur erforderlich, wenn Sie in der Anfrage auch willPauseWhenDucked(true) oder setAcceptsDelayedFocusGain(true) angeben.

Es gibt zwei Methoden zum Festlegen des Listeners: eine mit und eine ohne Handler-Argument. Der Handler ist der Thread, in dem der Listener ausgeführt wird. Wenn Sie keinen Handler angeben, wird der Handler verwendet, der mit der HauptLooper verknüpft ist.

Im folgenden Beispiel wird gezeigt, wie Sie mit einem AudioFocusRequest.Builder einen AudioFocusRequest erstellen und den Audiofokus anfordern und aufheben:

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;
        }
    }
}

Automatisches Ducking

Wenn unter Android 8.0 (API-Ebene 26) eine andere App den Fokus mit AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK anfordert, kann das System die Lautstärke leiser stellen und wiederherstellen, ohne den onAudioFocusChange()-Callback der App aufzurufen.

Das automatische Ducking ist für Apps zur Musik- und Videowiedergabe akzeptabel, aber nicht für die Wiedergabe gesprochener Inhalte, z. B. in einer Hörbuch-App. In diesem Fall sollte die App stattdessen pausiert werden.

Wenn Ihre App bei einer Stummschaltung pausiert werden soll, anstatt die Lautstärke zu verringern, erstellen Sie eine OnAudioFocusChangeListener mit einer onAudioFocusChange()-Callback-Methode, die das gewünschte Pausieren/Fortsetzen implementiert. Rufe setOnAudioFocusChangeListener() auf, um den Listener zu registrieren, und rufe setWillPauseWhenDucked(true) auf, um dem System zu sagen, dass es deinen Callback verwenden soll, anstatt automatisch zu ducken.

Verzögerte Fokusgewinnung

Manchmal kann das System eine Anfrage für den Audiofokus nicht gewähren, weil der Fokus von einer anderen App „gesichert“ ist, z. B. während eines Anrufs. In diesem Fall gibt requestAudioFocus() AUDIOFOCUS_REQUEST_FAILED zurück. In diesem Fall sollte Ihre App die Audiowiedergabe nicht fortsetzen, da sie nicht den Fokus erhalten hat.

Die Methode setAcceptsDelayedFocusGain(true), mit der Ihre App eine Anfrage für den Fokus asynchron verarbeiten kann. Wenn dieses Flag gesetzt ist, wird für eine Anfrage, die bei gesperrtem Fokus gesendet wird, AUDIOFOCUS_REQUEST_DELAYED zurückgegeben. Wenn die Bedingung, die den Audiofokus gesperrt hat, nicht mehr erfüllt ist, z. B. wenn ein Anruf endet, gewährt das System die ausstehende Fokusanfrage und ruft onAudioFocusChange() auf, um Ihre App zu benachrichtigen.

Um die verzögerte Fokussierung zu verarbeiten, müssen Sie ein OnAudioFocusChangeListener mit einer onAudioFocusChange()-Callback-Methode erstellen, die das gewünschte Verhalten implementiert. Registrieren Sie dann den Listener durch Aufrufen von setOnAudioFocusChangeListener().

Audiofokus unter Android 7.1 und niedriger

Wenn Sie requestAudioFocus() aufrufen, müssen Sie einen Dauerhinweis angeben, der von einer anderen App berücksichtigt werden kann, die gerade den Fokus hat und wiedergegeben wird:

  • Fordere den dauerhaften Audiofokus (AUDIOFOCUS_GAIN) an, wenn du vorhast, in absehbarer Zeit Audioinhalte abzuspielen (z. B. Musik) und davon ausgehst, dass der vorherige Inhaber des Audiofokus die Wiedergabe beendet.
  • Fordere den vorübergehenden Fokus (AUDIOFOCUS_GAIN_TRANSIENT) an, wenn du Audio nur für kurze Zeit wiedergeben möchtest und der vorherige Inhaber die Wiedergabe pausieren soll.
  • Fordere den vorübergehenden Fokus mit Ducking (AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) an, um anzugeben, dass du Audio nur für kurze Zeit abspielen möchtest und dass der vorherige Fokusinhaber die Wiedergabe fortsetzen darf, wenn er seine Audioausgabe leiser stellt. Beide Audioausgaben werden in den Audiostream eingemischt. Ducking eignet sich besonders für Apps, bei denen der Audiostream nur zeitweise verwendet wird, z. B. für hörbare Navigationsanweisungen.

Für die Methode requestAudioFocus() ist außerdem eine AudioManager.OnAudioFocusChangeListener erforderlich. Dieser Listener sollte in derselben Aktivität oder demselben Dienst erstellt werden, zu dem Ihre Mediensitzung gehört. Es implementiert den Rückruf onAudioFocusChange(), den Ihre App erhält, wenn eine andere App den Audiofokus erhält oder aufgibt.

Im folgenden Snippet wird der dauerhafte Audiofokus auf den Stream STREAM_MUSIC angefordert und ein OnAudioFocusChangeListener registriert, um nachfolgende Änderungen des Audiofokus zu verarbeiten. (Der Änderungslistener wird unter Auf eine Änderung des Audiofokus reagieren beschrieben.)

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
}

Wenn Sie die Wiedergabe beendet haben, rufen Sie abandonAudioFocus() auf.

Kotlin

audioManager.abandonAudioFocus(afChangeListener)

Java

// Abandon audio focus when playback complete
audioManager.abandonAudioFocus(afChangeListener);

Dadurch wird das System darüber informiert, dass Sie den Fokus nicht mehr benötigen, und die zugehörige OnAudioFocusChangeListener wird abgemeldet. Wenn Sie den vorübergehenden Fokus angefordert haben, wird eine App, die pausiert oder stummgeschaltet wurde, benachrichtigt, dass sie die Wiedergabe fortsetzen oder die Lautstärke wiederherstellen kann.

Auf eine Änderung des Audiofokus reagieren

Wenn eine App den Audiofokus erhält, muss sie ihn freigeben können, wenn eine andere App den Audiofokus für sich anfordert. In diesem Fall wird in Ihrer App die Methode onAudioFocusChange() im AudioFocusChangeListener aufgerufen, das Sie beim Aufrufen von requestAudioFocus() angegeben haben.

Der an onAudioFocusChange() übergebene Parameter focusChange gibt die Art der Änderung an. Er entspricht dem Dauerhinweis, der von der App verwendet wird, die den Fokus erhält. Ihre App sollte entsprechend reagieren.

Vorübergehender Fokusverlust
Wenn die Fokusänderung vorübergehend ist (AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK oder AUDIOFOCUS_LOSS_TRANSIENT), sollte Ihre App die Lautstärke reduzieren (sofern Sie nicht auf die automatische Stummschaltung zurückgreifen) oder die Wiedergabe pausieren, aber ansonsten denselben Status beibehalten.

Bei einem vorübergehenden Verlust des Audiofokus solltest du die Änderungen am Audiofokus weiterhin beobachten und bereit sein, die normale Wiedergabe fortzusetzen, sobald der Fokus wiederhergestellt ist. Wenn die blockierende App den Fokus verliert, erhalten Sie einen Rückruf (AUDIOFOCUS_GAIN). Jetzt können Sie die Lautstärke wieder auf das normale Niveau bringen oder die Wiedergabe fortsetzen.

Dauerhafter Verlust des Fokus
Wenn der Audiofokus dauerhaft verloren geht (AUDIOFOCUS_LOSS), spielt eine andere App Audioinhalte ab. Deine App sollte die Wiedergabe sofort pausieren, da sie keinen AUDIOFOCUS_GAIN-Callback erhält. Wenn die Wiedergabe fortgesetzt werden soll, muss der Nutzer eine explizite Aktion ausführen, z. B. die Wiedergabesteuerung in einer Benachrichtigung oder App-Benutzeroberfläche drücken.

Das folgende Code-Snippet zeigt, wie OnAudioFocusChangeListener und sein onAudioFocusChange()-Callback implementiert werden. Beachten Sie, dass mit Handler der Rückruf bei Beendigung bei dauerhaftem Verlust des Audiofokus verzögert wird.

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
      }
    }
  };

Der Handler verwendet eine Runnable, die so aussieht:

Kotlin

private var delayedStopRunnable = Runnable {
    mediaController.transportControls.stop()
}

Java

private Runnable delayedStopRunnable = new Runnable() {
    @Override
    public void run() {
        getMediaController().getTransportControls().stop();
    }
};

Damit die verzögerte Beendigung nicht ausgelöst wird, wenn der Nutzer die Wiedergabe neu startet, rufe mHandler.removeCallbacks(mDelayedStopRunnable) als Reaktion auf Statusänderungen auf. Rufen Sie removeCallbacks() beispielsweise in onPlay(), onSkipToNext() usw. Ihres Callbacks auf. Sie sollten diese Methode auch im onDestroy()-Callback Ihres Dienstes aufrufen, wenn Sie die vom Dienst verwendeten Ressourcen bereinigen.