Audiofokus verwalten

Zwei oder mehr Android-Apps können Audioinhalte gleichzeitig über denselben Ausgabestream wiedergeben und das System vermischt alles. Das ist zwar technisch beeindruckend, kann aber für Nutzer sehr ärgerlich sein. Damit nicht jede Musik-App gleichzeitig abgespielt wird, führt Android das Konzept des Audiofokus ein. Der Audiofokus kann jeweils nur von einer App gehalten werden.

Wenn Ihre App Audio ausgeben muss, sollte sie den Audiofokus anfordern. Wenn es fokussiert ist, kann es Ton wiedergeben. Nachdem Sie den Audiofokus erhalten haben, können Sie ihn aber möglicherweise nicht behalten, bis Sie fertig sind. Eine andere App kann einen Fokus anfordern, wodurch das Halten des Audiofokus vorzeitig beendet 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 dazu angehalten, die Richtlinien für den Audiofokus einzuhalten. Wenn eine App jedoch 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 Anwendung beeinträchtigt jedoch die Nutzerfreundlichkeit und kann dazu führen, dass Nutzer die fehlerhafte App deinstallieren.

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

  • Rufen Sie requestAudioFocus() unmittelbar vor Beginn der Wiedergabe 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, können Sie die Wiedergabe stoppen oder pausieren oder die Lautstärke verringern.

  • Verlassen Sie den Audiofokus, wenn die Wiedergabe beendet wird, z. B. wenn in der App nichts mehr zur Verfügung steht. Ihre App muss den Audiofokus nicht verlassen, wenn der Nutzer die Wiedergabe pausiert, aber möglicherweise später wieder ansetzt.

  • Verwende AudioAttributes, um zu beschreiben, welche Art von Audio deine App wiedergibt. Geben Sie beispielsweise für Anwendungen, die Sprache wiedergeben, CONTENT_TYPE_SPEECH an.

Der Audiofokus wird je nach ausgeführter Android-Version unterschiedlich gehandhabt:

Android 12 (API-Level 31) oder höher
Der Audiofokus wird vom System verwaltet. Das System erzwingt, dass die Audiowiedergabe in einer App ausgeblendet wird, wenn eine andere App den Audiofokus anfordert. Das System schaltet außerdem die Audiowiedergabe bei einem eingehenden Anruf stumm.
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-Level 26) eingeführt wurden.
Android 7.1 (API-Level 25) und niedriger
Der Audiofokus wird nicht vom System verwaltet und Apps verwalten den Audiofokus mithilfe von requestAudioFocus() und abandonAudioFocus().

Audiofokus in Android 12 und höher

Eine Medien- oder Spiele-App, die den Audiofokus verwendet, sollte keine Audioinhalte mehr wiedergeben, wenn sie den Fokus verliert. Ab Android 12 (API-Level 31) und höher wird dieses Verhalten durch das System erzwungen. Wenn eine App den Audiofokus anfordert, während eine andere App im Fokus ist und wiedergegeben wird, erzwingt das System das Ausblenden der abspielenden App. Das Hinzufügen der Ausblendung ermöglicht einen reibungsloseren Übergang beim Wechsel von einer App zur anderen.

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

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

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

Wenn diese Bedingungen erfüllt sind, wird die erste App vom Audiosystem ausgeblendet. Am Ende der Ausblenden benachrichtigt das System die erste App über Fokusverlust. Die Player der App bleiben stummgeschaltet, bis die App wieder den Audiofokus anfordert.

Vorhandenes Verhalten des Audiofokus

Sie sollten auch auf diese anderen Fälle achten, bei denen ein Schalter im Audiofokus verwendet wird.

Automatisches Entladen

Automatisches Ducking (die vorübergehende Reduzierung des Audiopegels einer App, damit eine andere deutlich zu hören ist) wurde in Android 8.0 (API-Level 26) eingeführt.

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

Automatisches Ducking tritt auch auf, wenn der Fokus einer Audiobenachrichtigung von einer laufenden App liegt. Der Beginn der Benachrichtigungswiedergabe wird mit dem Ende der Ducking-Rampe synchronisiert.

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

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

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

Sind diese Bedingungen erfüllt, werden alle aktiven Spieler der ersten App vom Audiosystem herausgefiltert, während die zweite App im Fokus ist. Wenn die zweite App nicht mehr den Fokus aufnimmt, werden sie wieder entfernt. Die erste App wird nicht benachrichtigt, wenn sie den Fokus verliert, sodass sie nichts tun muss.

Beachten Sie, dass automatisches Ducking nicht ausgeführt wird, wenn der Nutzer Sprachinhalte anhört, da er möglicherweise einen Teil des Programms übersehen könnte. Beispielsweise wird die Sprachführung für Wegbeschreibungen nicht verdunkelt.

Aktuelle Audiowiedergabe für eingehende Anrufe stummschalten

Einige Apps funktionieren nicht richtig und führen die Audiowiedergabe bei Anrufen nicht weiter. In dieser Situation muss der Nutzer die anstößige App suchen und stummschalten oder beenden, um den Anruf zu hören. Um dies zu verhindern, kann das System den Ton von anderen Apps während eines eingehenden Anrufs stummschalten. Das System ruft diese Funktion auf, wenn ein eingehender Anruf eingeht 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 Fokuserhöhung) angefordert und gibt Audio wieder.

Wird die Wiedergabe einer App während des Anrufs fortgesetzt, wird sie stummgeschaltet, bis der Anruf beendet wird. Wenn eine App jedoch während des Aufrufs mit der Wiedergabe beginnt, wird dieser Player nicht in der Annahme, dass der Nutzer die Wiedergabe absichtlich gestartet hat, stummgeschaltet.

Audiofokus unter Android 8.0 bis Android 11

Ab Android 8.0 (API-Level 26) musst du beim Aufrufen von requestAudioFocus() einen AudioFocusRequest-Parameter angeben. Das AudioFocusRequest enthält Informationen zum Audiokontext und zu den Funktionen Ihrer App. Das System verwendet diese Informationen, um Verstärkung und Verlust des Audiofokus automatisch zu steuern. Wenn Sie den Audiofokus freigeben möchten, rufen Sie die Methode abandonAudioFocusRequest() auf, die auch ein AudioFocusRequest als Argument verwendet. Verwenden Sie dieselbe AudioFocusRequest-Instanz sowohl, wenn Sie den Fokus anfordern als auch verwerfen.

Verwenden Sie zum Erstellen eines AudioFocusRequest eine AudioFocusRequest.Builder. Da bei einer Fokusanfrage 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 die gleichen Werte wie der durationHint verwendet, der vor Android 8.0 im Aufruf von requestAudioFocus() verwendet wurde: AUDIOFOCUS_GAIN, AUDIOFOCUS_GAIN_TRANSIENT, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK oder AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE.
setAudioAttributes() AudioAttributes beschreibt den Anwendungsfall für Ihre Anwendung. Das System prüft sie, wenn eine App den Audiofokus erhält bzw. verliert. Attribute ersetzen das Konzept des Streamtyps. In Android 8.0 (API-Level 26) und höher werden Streamtypen für alle Vorgänge mit Ausnahme der Lautstärkeregelung eingestellt. Verwenden Sie für die Fokusanfrage dieselben Attribute wie im Audioplayer (wie im Beispiel nach dieser Tabelle gezeigt).

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

Wenn keine Angabe erfolgt, wird für AudioAttributes standardmäßig AudioAttributes.USAGE_MEDIA verwendet.

setWillPauseWhenDucked() Wenn eine andere Anwendung den Fokus mit AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK anfordert, erhält diese Anwendung in der Regel keinen onAudioFocusChange()-Callback, da das System das Ducking selbst vornehmen kann. Wenn Sie die Wiedergabe pausieren müssen, anstatt die Lautstärke zu verringern, rufen Sie setWillPauseWhenDucked(true) auf, erstellen Sie ein OnAudioFocusChangeListener und legen Sie es fest, wie unter Automatisches Eindocken beschrieben.
setAcceptsDelayedFocusGain() Eine Anfrage für den Audiofokus kann fehlschlagen, wenn der Fokus durch eine andere App gesperrt wird. Diese Methode ermöglicht die verzögerte Fokuserhöhung, d. h. die Möglichkeit, den Fokus asynchron zu erfassen, wenn er verfügbar wird.

Beachten Sie, dass die verzögerte Fokuserhöhung nur funktioniert, wenn Sie in der Audioanfrage auch ein AudioManager.OnAudioFocusChangeListener angeben, da Ihre 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 zum Festlegen des Listeners: eine mit und eine ohne Handler-Argument. Der Handler ist der Thread, auf dem der Listener ausgeführt wird. Wenn Sie keinen Handler angeben, wird der Handler verwendet, der dem Haupt-Looper zugeordnet ist.

Das folgende Beispiel zeigt, wie Sie mit AudioFocusRequest.Builder ein AudioFocusRequest erstellen und den Audiofokus anfordern und verwerfen können:

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 Entladen

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

Automatisches Ducking ist zwar für Apps zur Musik- und Videowiedergabe akzeptabel, bei der Wiedergabe von gesprochenen Inhalten, z. B. in einer Hörbuch-App, jedoch nicht nützlich. In diesem Fall sollte die App stattdessen pausiert werden.

Wenn Sie möchten, dass Ihre App bei Aufforderung zum Ducken pausiert, anstatt die Lautstärke zu verringern, erstellen Sie ein 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 setWillPauseWhenDucked(true), um das System anzuweisen, Ihren Callback zu verwenden, anstatt automatisches Ducking durchzuführen.

Verzögerte Fokussierung

Manchmal kann das System keine Anfrage für den Audiofokus genehmigen, weil der Fokus von einer anderen App, z. B. während eines Telefonanrufs, "gesperrt" wurde. In diesem Fall gibt requestAudioFocus() AUDIOFOCUS_REQUEST_FAILED zurück. In diesem Fall sollte Ihre App nicht mit der Audiowiedergabe fortfahren, da sie den Fokus nicht verstärkt.

Die Methode setAcceptsDelayedFocusGain(true), mit der Ihre Anwendung eine Anfrage für den asynchronen Fokus verarbeiten kann. Wenn dieses Flag gesetzt ist, gibt eine Anfrage, die bei gesperrtem Fokus gestellt wurde, AUDIOFOCUS_REQUEST_DELAYED zurück. Wenn die Bedingung, durch die der Audiofokus gesperrt wurde, nicht mehr besteht, z. B. wenn ein Telefonanruf endet, erteilt das System die ausstehende Fokusanfrage und ruft onAudioFocusChange() auf, um die App zu benachrichtigen.

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

Audiofokus unter Android 7.1 und niedriger

Wenn du requestAudioFocus() aufrufst, musst du einen Hinweis für die Dauer angeben, der von einer anderen App übernommen werden kann, die derzeit den Fokus hält und spielt:

  • Fordern Sie einen dauerhaften Audiofokus (AUDIOFOCUS_GAIN) an, wenn Sie auf absehbare Zeit Audio wiedergeben möchten (z. B. bei der Musikwiedergabe), und Sie erwarten, dass der vorherige Inhaber des Audiofokus die Wiedergabe beenden wird.
  • Fordern Sie den vorübergehenden Fokus (AUDIOFOCUS_GAIN_TRANSIENT) an, wenn die Audiowiedergabe voraussichtlich nur für kurze Zeit erfolgt und Sie erwarten, dass der vorherige Inhaber die Wiedergabe pausiert.
  • Fordern Sie mit Ducking (AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) den vorübergehenden Fokus an, um anzugeben, dass Sie Audio vermutlich nur für kurze Zeit wiedergeben und dass der vorherige Fokusinhaber die Wiedergabe fortsetzen darf, wenn er die Audioausgabe „duckt“ (verringert). Beide Audioausgänge werden in den Audiostream gemischt. Ducking eignet sich besonders für Apps, die den Audiostream unregelmäßig nutzen, z. B. für hörbare Wegbeschreibungen.

Für die Methode requestAudioFocus() ist außerdem ein AudioManager.OnAudioFocusChangeListener erforderlich. Dieser Listener sollte in derselben Aktivität oder in demselben Dienst erstellt werden, der auch Ihre Mediensitzung besitzt. Er implementiert den Callback-onAudioFocusChange(), den deine App empfängt, wenn eine andere App den Audiofokus aktiviert oder aufhebt.

Mit dem folgenden Snippet wird der dauerhafte Audiofokus für den Stream STREAM_MUSIC angefordert und ein OnAudioFocusChangeListener registriert, um nachfolgende Änderungen am Audiofokus zu verarbeiten. Der Änderungs-Listener wird unter Reagieren auf eine Änderung des Audiofokus 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
}

Rufen Sie nach Abschluss der Wiedergabe 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 keinen Fokus mehr benötigen, und die Registrierung der zugehörigen OnAudioFocusChangeListener wird aufgehoben. Wenn Sie den vorübergehenden Fokus angefordert haben, wird eine pausierte oder verdunkelte App darüber informiert, dass die Wiedergabe fortgesetzt 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 selbst anfordert. In diesem Fall erhält Ihre Anwendung einen Aufruf an die Methode onAudioFocusChange() in der AudioFocusChangeListener, die Sie beim Aufrufen der Anwendung requestAudioFocus() angegeben haben.

Der an onAudioFocusChange() übergebene Parameter focusChange gibt die Art der Änderung an. Es entspricht dem Hinweis für die Dauer, der von der App verwendet wird, die den Fokus erhält. Ihre App sollte angemessen reagieren.

Vorübergehender Fokusverlust
Bei einer vorübergehenden Fokusänderung (AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK oder AUDIOFOCUS_LOSS_TRANSIENT) sollte Ihre App ducken (falls Sie kein automatisches Ducken verwenden) oder die Wiedergabe pausieren, aber ansonsten denselben Status beibehalten.

Während eines vorübergehenden Verlusts des Audiofokus sollten Sie den Audiofokus weiterhin beobachten und darauf vorbereitet sein, die normale Wiedergabe fortzusetzen, sobald der Fokus wieder hergestellt ist. Wenn der Fokus der blockierenden App nicht mehr angezeigt wird, erhalten Sie einen Callback (AUDIOFOCUS_GAIN). Anschließend können Sie die Lautstärke auf die normale Lautstärke wiederherstellen oder die Wiedergabe neu starten.

Dauerhafter Fokusverlust
Wenn der Audiofokus dauerhaft verloren geht (AUDIOFOCUS_LOSS), spielt eine andere App Audio ab. Die App sollte die Wiedergabe sofort anhalten, da sie keinen AUDIOFOCUS_GAIN-Callback erhält. Um die Wiedergabe neu zu starten, muss der Nutzer eine explizite Aktion ausführen, z. B. das Steuerelement „Transport wiedergeben“ in einer Benachrichtigung oder App-Benutzeroberfläche.

Das folgende Code-Snippet zeigt, wie OnAudioFocusChangeListener und dessen onAudioFocusChange()-Callback implementiert werden. Beachten Sie die Verwendung von 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 einen Runnable, der 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 aktiviert wird, wenn der Nutzer die Wiedergabe neu startet, rufen Sie als Reaktion auf Statusänderungen mHandler.removeCallbacks(mDelayedStopRunnable) auf. Rufen Sie beispielsweise removeCallbacks() in den 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.