Audiofokus verwalten

Zwei oder mehr Android-Apps können gleichzeitig Audio im selben Ausgabestream abspielen und das System mischt alles zusammen. Das ist zwar technisch beeindruckend, kann für Nutzer aber sehr ärgerlich sein. Damit nicht alle Musik-Apps gleichzeitig wiedergegeben werden, gibt es in Android das Konzept des Audiofokus. Es kann immer nur eine App den Audiofokus haben.

Wenn Ihre App Audio ausgeben muss, sollte sie den Audiofokus anfordern. Wenn sie im Fokus ist, kann sie Ton wiedergeben. Nachdem du den Audiofokus erhalten hast, kannst du ihn jedoch möglicherweise nicht bis zum Ende der Wiedergabe behalten. Eine andere App kann den Fokus anfordern, wodurch der Audiofokus von deiner App entfernt wird. In diesem Fall sollte die Wiedergabe in Ihrer App pausiert oder die Lautstärke verringert werden, 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 dazu angehalten, die Richtlinien für den Audiofokus einzuhalten, aber wenn eine App auch nach dem Verlust des Audiofokus auf einem Gerät mit Android 11 (API-Level 30) oder niedriger weiterhin laut wiedergegeben wird, kann das System dies nicht verhindern. Dieses Verhalten der App führt jedoch zu einer schlechten Nutzererfahrung und kann oft dazu führen, dass Nutzer die App deinstallieren.

Eine gut gestaltete Audio-App sollte den Audiofokus gemäß den folgenden allgemeinen Richtlinien verwalten:

  • Rufen Sie requestAudioFocus() unmittelbar vor dem Start des Spiels auf und prüfen Sie, ob der Aufruf AUDIOFOCUS_REQUEST_GRANTED zurückgibt. Rufen Sie requestAudioFocus() im onPlay()-Callback Ihrer Mediensitzung auf.

  • Wenn eine andere App den Audiofokus erhält, beende oder pausiere die Wiedergabe oder verringere die Lautstärke.

  • Wenn die Wiedergabe beendet wird (z. B. wenn die App nichts mehr abzuspielen hat), gib den Audiofokus auf. Ihre App muss den Audiofokus nicht aufgeben, wenn der Nutzer die Wiedergabe pausiert, sie aber später möglicherweise fortsetzt.

  • Verwende AudioAttributes, um den Typ der Audioinhalte zu beschreiben, die deine App wiedergibt. Geben Sie beispielsweise für Apps, die Sprache wiedergeben, CONTENT_TYPE_SPEECH an.

Der Audiofokus wird je nach Android-Version unterschiedlich gehandhabt:

Android 12 (API-Level 31) oder höher
Der Audiofokus wird vom System verwaltet. Das System erzwingt das Ausblenden der Audiowiedergabe einer App, wenn eine andere App den Audiofokus anfordert. Das System schaltet die Audiowiedergabe auch stumm, wenn ein eingehender Anruf eingeht.
Android 8.0 (API-Level 26) bis Android 11 (API-Level 30)
Der Audiofokus wird nicht vom System verwaltet, enthält aber einige Änderungen, die ab Android 8.0 (API-Level 26) eingeführt wurden.
Android 7.1 (API-Level 25) und niedriger
Der Audiofokus wird nicht vom System verwaltet. Apps verwalten den Audiofokus mit requestAudioFocus() und abandonAudioFocus().

Audiofokus in Android 12 und höher

Eine Medien- oder Gaming-App, die den Audiofokus verwendet, sollte keine Audioinhalte wiedergeben, nachdem sie den Fokus verloren hat. Unter Android 12 (API-Level 31) und höher wird dieses Verhalten vom System erzwungen. Wenn eine App den Audiofokus anfordert, während eine andere App den Fokus hat und Audio wiedergibt, erzwingt das System das Ausblenden der wiedergebenden App. Das Ausblenden sorgt für einen flüssigeren Übergang beim Wechsel von einer App zu einer anderen.

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

  1. Die erste, gerade wiedergegebene App erfüllt alle diese Kriterien:

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

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

Bestehendes Verhalten des Audiofokus

Du solltest auch die folgenden Fälle kennen, in denen der Audiofokus wechselt.

Automatisches Ducking

Das automatische Ducking (vorübergehendes Reduzieren des Audiopegels einer App, damit eine andere App deutlich zu hören ist) wurde in Android 8.0 (API-Level 26) eingeführt.

Wenn das System das Ducking implementiert, müssen Sie es nicht in Ihrer App implementieren.

Eine automatische Absenkung erfolgt auch, wenn eine Audiobenachrichtigung den Fokus von einer wiedergegebenen App übernimmt. Der Beginn der Wiedergabe der Benachrichtigung wird mit dem Ende der Absenkung synchronisiert.

Das automatische Ducking erfolgt, wenn die folgenden Bedingungen erfüllt sind:

  1. Die erste App, die gerade wiedergegeben wird, erfüllt alle diese Kriterien:

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

Wenn diese Bedingungen erfüllt sind, werden alle aktiven Player der ersten App vom Audiosystem geduckt, während die zweite App im Fokus ist. Wenn die zweite App den Fokus verliert, wird die Lautstärke wieder erhöht. Die erste App wird nicht benachrichtigt, wenn sie den Fokus verliert, und muss daher nichts tun.

Beachte, dass das automatische Ducking nicht durchgeführt wird, wenn der Nutzer Sprachinhalte hört, da er sonst möglicherweise einen Teil des Programms verpasst. Die Sprachführung für Wegbeschreibungen wird beispielsweise nicht geduckt.

Aktuelle Audiowiedergabe bei eingehenden Anrufen stummschalten

Einige Apps funktionieren nicht richtig und spielen während Telefonaten weiterhin Audio ab. In dieser Situation muss der Nutzer die störende 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 eingehender 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 (beliebiger Fokusgewinn) angefordert und gibt Audio wieder.

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

Audiofokus in Android 8.0 bis Android 11

Ab Android 8.0 (API-Level 26) müssen Sie beim Aufrufen 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 freigeben möchten, rufen Sie die Methode abandonAudioFocusRequest() auf, die ebenfalls ein AudioFocusRequest als Argument akzeptiert. Verwenden Sie dieselbe AudioFocusRequest-Instanz, wenn Sie den Fokus anfordern und wenn Sie ihn aufgeben.

Verwenden Sie zum Erstellen eines AudioFocusRequest einen AudioFocusRequest.Builder. Da bei einer Fokus-Anfrage immer der Typ der Anfrage 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 erforderlich. Alle anderen Felder sind optional.

MethodeHinweise
setFocusGain() Dieses Feld ist bei jeder Anfrage erforderlich. Es werden dieselben Werte wie für durationHint verwendet, die im Aufruf von requestAudioFocus() vor Android 8.0 verwendet wurden: AUDIOFOCUS_GAIN, AUDIOFOCUS_GAIN_TRANSIENT, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK oder AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE.
setAudioAttributes() AudioAttributes beschreibt den Anwendungsfall für deine App. Das System berücksichtigt sie, wenn eine App den Audiofokus erhält und verliert. Attribute ersetzen das Konzept des Streamtyps. In Android 8.0 (API-Level 26) und höher sind Streamtypen für alle Vorgänge außer der Lautstärkeregelung verworfen. Verwende in der Fokus-Anfrage dieselben Attribute wie im Audioplayer (siehe Beispiel nach dieser Tabelle).

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

Wenn nicht angegeben, wird AudioAttributes standardmäßig auf AudioAttributes.USAGE_MEDIA gesetzt.

setWillPauseWhenDucked() Wenn eine andere App den Fokus mit AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK anfordert, erhält die App, die den Fokus hat, normalerweise keinen onAudioFocusChange()-Callback, da das System das Ducking selbst durchführen kann. Wenn du die Wiedergabe pausieren möchtest, anstatt die Lautstärke zu verringern, rufe setWillPauseWhenDucked(true) auf und erstelle und setze ein OnAudioFocusChangeListener, wie unter Automatisches Ducking beschrieben.
setAcceptsDelayedFocusGain() Eine Anfrage für den Audiofokus kann fehlschlagen, wenn der Fokus von einer anderen App gesperrt ist. Diese Methode ermöglicht die verzögerte Fokuserlangung: die Möglichkeit, den Fokus asynchron zu erlangen, wenn er verfügbar wird.

Beachte, dass die verzögerte Fokuserlangung nur funktioniert, wenn du in der Audioanfrage auch einen AudioManager.OnAudioFocusChangeListener angibst, da deine App den Callback empfangen 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, um den Listener festzulegen: 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 Haupt-Looper verknüpft ist.

Das folgende Beispiel zeigt, wie Sie mit einem AudioFocusRequest.Builder ein AudioFocusRequest erstellen und den Audiofokus anfordern und aufgeben:

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-Level 26) eine andere App den Fokus mit AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK anfordert, kann das System die Lautstärke verringern und wiederherstellen, ohne den onAudioFocusChange()-Callback der App aufzurufen.

Während das automatische Ducking für Musik- und Videowiedergabe-Apps akzeptabel ist, ist es bei der Wiedergabe von gesprochenen Inhalten, z. B. in einer Hörbuch-App, nicht nützlich. In diesem Fall sollte die App stattdessen pausieren.

Wenn du möchtest, dass deine App pausiert, wenn sie zum Ducking aufgefordert wird, anstatt die Lautstärke zu verringern, erstelle einen OnAudioFocusChangeListener mit einer onAudioFocusChange()-Callback-Methode, die das gewünschte Verhalten zum Pausieren/Fortsetzen implementiert. Rufen Sie setOnAudioFocusChangeListener() auf, um den Listener zu registrieren, und rufen Sie setWillPauseWhenDucked(true) auf, um das System anzuweisen, Ihren Callback zu verwenden, anstatt automatisches Ducking durchzuführen.

Verzögerter Fokusgewinn

Manchmal kann das System eine Anfrage für den Audiofokus nicht gewähren, weil der Fokus durch eine andere App „gesperrt“ ist, z. B. während eines Telefonats. In diesem Fall gibt requestAudioFocus() AUDIOFOCUS_REQUEST_FAILED zurück. In diesem Fall sollte die Audiowiedergabe in Ihrer App nicht fortgesetzt werden, da sie den Fokus nicht erhalten hat.

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

Um den verzögerten Fokusgewinn zu verarbeiten, müssen Sie einen OnAudioFocusChangeListener mit einer onAudioFocusChange()-Callback-Methode erstellen, die das gewünschte Verhalten implementiert, und den Listener durch Aufrufen von setOnAudioFocusChangeListener() registrieren.

Audiofokus in Android 7.1 und niedriger

Wenn du requestAudioFocus() aufrufst, musst du einen Hinweis zur Dauer angeben, der von einer anderen App berücksichtigt werden kann, die gerade den Fokus hat und etwas wiedergibt:

  • Fordere den permanenten Audiofokus (AUDIOFOCUS_GAIN) an, wenn du planst, Audioinhalte für absehbare Zeit abzuspielen (z. B. beim Abspielen von Musik) und du erwartest, dass der vorherige Inhaber des Audiofokus die Wiedergabe beendet.
  • Fordere einen vorübergehenden Fokus (AUDIOFOCUS_GAIN_TRANSIENT) an, wenn du Audio nur für kurze Zeit abspielen möchtest und erwartest, dass der vorherige Inhaber die Wiedergabe pausiert.
  • Fordere einen vorübergehenden Fokus mit Ducking (AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) an, um anzugeben, dass du Audioinhalte nur für kurze Zeit abspielen möchtest und dass der vorherige Fokusinhaber die Wiedergabe fortsetzen kann, wenn er die Audioausgabe „duckt“ (verringert). Beide Audioausgaben werden in den Audiostream gemischt. Ducking eignet sich besonders für Apps, die den Audiostream nur gelegentlich verwenden, z. B. für gesprochene Wegbeschreibungen.

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

Im folgenden Snippet wird ein dauerhafter Audiofokus für den Stream STREAM_MUSIC angefordert und ein OnAudioFocusChangeListener registriert, um nachfolgende Änderungen am Audiofokus zu verarbeiten. (Der Änderungs-Listener wird unter Auf eine Änderung des Audiofokus reagieren erläutert.)

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 die Wiedergabe beendet ist, 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 Registrierung des zugehörigen OnAudioFocusChangeListener wird aufgehoben. Wenn du einen vorübergehenden Fokus angefordert hast, wird eine App, die pausiert oder die Lautstärke verringert hat, darüber informiert, 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 erhält Ihre App einen Aufruf der Methode onAudioFocusChange() in der AudioFocusChangeListener, die Sie beim Aufruf 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 verringern (wenn Sie nicht auf automatisches Ducking setzen) oder die Wiedergabe pausieren, aber ansonsten den gleichen Status beibehalten.

Während eines vorübergehenden Verlusts des Audiofokus solltest du weiterhin Änderungen am Audiofokus beobachten und darauf vorbereitet sein, die normale Wiedergabe fortzusetzen, wenn du den Fokus wiedererlangst. Wenn die blockierende App den Fokus aufgibt, erhältst du einen Callback (AUDIOFOCUS_GAIN). Jetzt kannst du die Lautstärke wieder auf das normale Niveau zurücksetzen oder die Wiedergabe neu starten.

Dauerhafter Verlust des Fokus
Wenn der Audiofokus dauerhaft verloren geht (AUDIOFOCUS_LOSS), spielt eine andere App Audio ab. Die App sollte die Wiedergabe sofort pausieren, da sie nie einen AUDIOFOCUS_GAIN-Callback erhält. Um die Wiedergabe neu zu starten, 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 die OnAudioFocusChangeListener und der zugehörige onAudioFocusChange()-Callback implementiert werden. Beachten Sie die Verwendung eines Handler, um den Stopp-Callback bei einem dauerhaften Verlust des Audiofokus zu verzögern.

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 der verzögerte Stopp nicht ausgelöst wird, wenn der Nutzer die Wiedergabe neu startet, rufe mHandler.removeCallbacks(mDelayedStopRunnable) als Reaktion auf alle Statusänderungen auf. Rufen Sie beispielsweise removeCallbacks() in onPlay(), onSkipToNext() usw. Ihres Callbacks auf. Sie sollten diese Methode auch im onDestroy()-Callback Ihres Dienstes aufrufen, wenn Sie die von Ihrem Dienst verwendeten Ressourcen bereinigen.