Ses odağını yönet

İki veya daha fazla Android uygulaması aynı çıkış akışında ses çalabilir hazırlıyor ve sistem her şeyi karıştırıyor. Bu ancak teknik açıdan etkileyici, ancak kullanıcıyı son derece rahatsız edebilir. Her bir aynı anda çalan bir müzik uygulamasıyla birlikte Android, ses odak. Aynı anda yalnızca bir uygulama ses odağını koruyabilir.

Uygulamanızın ses çıkışını alması gerektiğinde ses odağı istemesi gerekir. Şu olduğunda: ses çalabilir. Ancak, ses odağını edindikten sonra bitene kadar saklamaya devam edebilirsiniz. Başka bir uygulama odaklanma isteğinde bulunabilir. Bu da ses odağını beklemeye alır. Bu durumda uygulamanız duraklatılır kullanıcıların yeni ses kaynağını daha kolay duyabilmesi için çalabilir veya sesini kısın.

Ses odağı, Android 12'den (API düzeyi 31) önce sistem tarafından yönetilmez. Dolayısıyla, uygulama geliştiricilerin ses odağı yönergelerine uymaları teşvik edilirken, Bir uygulama, cihazdaki ses odağını kaybetmiş olsa bile yüksek sesle çalmaya devam ederse sistem bunu engelleyemez. Ancak bu uygulama davranışı kötü bir kullanıcı deneyimine yol açıyor ve çoğunlukla uygulamayı kaldırmalarını isteyin.

İyi tasarlanmış bir ses uygulaması, ses odağını burada belirtilen genel kurallar:

  • Oynamaya başlamadan hemen önce requestAudioFocus() adlı satıcıyı arayın ve şunu doğrulayın: çağrı AUDIOFOCUS_REQUEST_GRANTED Şunu ara: Medya oturumunuzun onPlay() geri çağırmasında requestAudioFocus().

  • Başka bir uygulama sese odaklandığında, çalmayı durdurduğunda veya duraklattığında ya da içeriğin sesini kısmak (yani ses düzeyini düşürebilirsiniz.

  • Oynatma durduğunda (örneğin, uygulamada oynatacak bir şey kalmadığında) ses odağını terk eder. Kullanıcı aşağıdaki durumlarda ses odağını terk etmek zorunda değildir: çalmayı duraklatır, ancak oynatmaya daha sonra devam edebilir.

  • Açıklama için AudioAttributes simgesini kullanın uygulamanızın çaldığı ses türü Örneğin, konuşma oynatan uygulamalarda belirtin CONTENT_TYPE_SPEECH.

Ses odağı, ilgili Android sürümüne bağlı olarak farklı şekillerde işlenir. çalışıyor:

Android 12 (API düzeyi 31) veya sonraki sürümler
Ses odağı sistem tarafından yönetilir. Sistem, başka bir uygulama ses odağı istediğinde uygulama kararır. Sistem ayrıca gelen bir arama alındığında ses çalmanın sesini kapatır.
Android 8.0 (API düzeyi 26) ile Android 11 (API düzeyi 30) arası
Ses odağı sistem tarafından yönetilmez, ancak ses odağının .
Android 7.1 (API düzeyi 25) ve önceki sürümler
Ses odağı sistem tarafından yönetilmez ve uygulamalar ses odağını şu komutlarla yönetir: requestAudioFocus() ve abandonAudioFocus().

Android 12 ve sonraki sürümlerde ses odağı

Ses odağını kullanan bir medya veya oyun uygulaması, kaybolduktan sonra ses çalmamalıdır odaklanacağız. Sistem, Android 12 (API düzeyi 31) ve sonraki sürümlerde gösterir. Bir uygulama ses odaklama isteğinde bulunurken başka bir uygulama odaklanıp sistem, oyun uygulamasını arkadan kapanmaya zorlar. Search Ads 360'a Kararma özelliği, uygulamalar arasında geçiş yaparken daha yumuşak bir geçiş sağlar.

Bu kaybolma davranışı, aşağıdaki koşullar karşılandığında gerçekleşir:

  1. Şu anda oynatılan ilk uygulama aşağıdaki kriterlerin tümünü karşılıyor:

  2. İkinci bir uygulama ise AudioManager.AUDIOFOCUS_GAIN ile ses odağı istiyor.

Bu koşullar karşılandığında ses sistemi, ilk uygulamadaki sesin yavaşlamasını sağlar. Şurada: kaybolduğunda sistem, ilk odak kaybı uygulamasına bildirim gönderir. Uygulamanın oynatıcıların sesi, uygulama tekrar ses odağı isteyene kadar kapalı kalır.

Mevcut ses odağı davranışları

Seste bir değiştirmenin olduğu diğer durumları da aklınızda bulundurun. odaklanacağız.

Otomatik kısma

Otomatik kısma (bir uygulamanın ses düzeyini, diğeri net bir şekilde duyulabiliyorsa) Android 8.0'da (API düzeyi 26) kullanıma sunuldu.

Sistemin yumuşatma uygulamasını sağladığınızda, arka plana almayı planlamanız gerekmez. en iyi şekilde yararlanabilirsiniz.

Odağı sesli bildirim aldığında da otomatik kısma görülür Google Play'den Bildirim oynatmanın başlangıcı senkronize edilir sonuna kadar bekleyin.

Otomatik kısma, aşağıdaki koşullar karşılandığında gerçekleşir:

  1. Şu anda oynatılan ilk uygulama aşağıdaki kriterlerin tümünü karşılıyor:

  2. İkinci bir uygulama, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK.

Bu koşullar karşılandığında ses sistemi, Google Play'deki tüm aktif ikinci uygulamaya odaklanılır. İkinci uygulama ayrıldığında dikkatlerini dağıtıyor. İlk uygulama odağı kaybettiğinde bilgilendirilmez. ve dolayısıyla herhangi bir şey yapması gerekmez.

Otomatik kısma, kullanıcı dinlerken gerçekleşmez. konuşma içeriğini kullanır, çünkü kullanıcı programın bir kısmını kaçırabilir. Örneğin, arabayla yol tariflerinde sesli yardımın kapanması engellenmiyor.

Gelen telefon aramalarında çalınan mevcut sesi kapat

Bazı uygulamalar düzgün çalışmıyor ve telefon aramaları sırasında ses çalmaya devam ediyor. Bu durum, kullanıcıyı rahatsız edici uygulamayı bulup sesini kapatmaya veya uygulamadan çıkmaya zorlar. duymak istiyor. Sistem, bunu önlemek için diğer gelen aramaları yapar. Bir gelen bir telefon araması alındığında ve bir uygulama aşağıdaki koşulları karşılıyorsa:

  • Uygulamada AudioAttributes.USAGE_MEDIA veya AudioAttributes.USAGE_GAME kullanım özelliği.
  • Uygulama başarıyla ses odağı (herhangi bir odak kazancı) istedi ve şu anda ses çalıyor ses'e dokunun.

Bir uygulama görüşme sırasında çalmaya devam ederse, o zamana kadar çalma sesi kapatılır. çağrı sona erer. Ancak arama sırasında bir uygulama oynatılmaya başlarsa bu oynatıcı kullanıcının videoyu kasıtlı olarak oynatmaya başladığı varsayımıyla sesi kıs.

Android 8.0 ile Android 11 arasındaki sürümlerde ses odağı

Android 8.0 (API düzeyi 26) sürümünden itibaren requestAudioFocus() bir AudioFocusRequest parametresi sağlamalısınız. AudioFocusRequest uygulamanızın ses bağlamı ve özellikleri hakkında bilgiler içerir. İlgili içeriği oluşturmak için kullanılan sistemi, bu bilgileri ses odağının kazanımını ve kaybını yönetmek için kullanır. otomatik olarak oluşturur. Ses odağını serbest bırakmak için yöntemi çağırın abandonAudioFocusRequest() Bu parametre de AudioFocusRequest bağımsız değişkeni olarak kabul edilir. Aynısını kullan AudioFocusRequest örneği hem istekte bulunduğunuzda hem de odağı terk ettiğinizde.

AudioFocusRequest oluşturmak için bir AudioFocusRequest.Builder. Odaklanma isteği isteğin türünü her zaman belirtin; tür, oluşturucuya dahil edilir bahsedeceğim. Diğer alanları ayarlamak için oluşturucunun yöntemlerini kullanın isteğinde bulunabilirsiniz.

FocusGain alanı zorunludur; diğer tüm alanlar isteğe bağlıdır.

YöntemNotlar
setFocusGain() Bu alan her istekte gereklidir. Bu, requestAudioFocus() ile yapılan Android 8.0 öncesi aramada kullanılan durationHint: AUDIOFOCUS_GAIN, AUDIOFOCUS_GAIN_TRANSIENT, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK veya AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE.
setAudioAttributes() AudioAttributes, uygulamanızın kullanım alanını açıklar. İlgili içeriği oluşturmak için kullanılan Uygulama ses odağını kazanıp kaybettiğinde sistem bunlara bakar. Öznitelikler akış türü kavramının yerini alır. Android 8.0 (API düzeyi 26) ve sonraki sürümlerde, ses kontrolleri dışındaki işlemler için akış türlerinin desteği sonlandırıldı. Tekliflerinizi otomatikleştirmek ve optimize etmek için odak isteğinizde, ses çalarınızda kullandığınız özelliklerin ( aşağıdaki tabloda gösterilmiştir).

Bir AudioAttributes.Builder kullanarak özelliklerini atayın, ardından bu yöntemi kullanarak isteğinde bulunabilirsiniz.

Belirtilmezse AudioAttributes, varsayılan olarak AudioAttributes.USAGE_MEDIA değerine ayarlanır.

setWillPauseWhenDucked() Başka bir uygulama AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, odağı olan uygulama genelde bir onAudioFocusChange() geri çağırmamızı sağlar çünkü sistem, kendiliğinden gizlenmesi gerekir. Oynatmayı duraklatmanız gerektiğinde sesi kısmak yerine setWillPauseWhenDucked(true) komutunu çağırın ve OnAudioFocusChangeListener, otomatik de olabilir.
setAcceptsDelayedFocusGain() Odak, başka bir uygulama tarafından kilitlendiğinde ses odağı isteği başarısız olabilir. Bu yöntem, gecikmeli odak kazanımı, yani yeterli kullanıma sunulduğunda eşzamansız olarak odağı elde etmek için

Gecikmeli odak kazancının yalnızca AudioManager.OnAudioFocusChangeListener. (sesli isteğe bağlı olarak) öğrenmek için geri aramayı alabilirsiniz.

setOnAudioFocusChangeListener() OnAudioFocusChangeListener yalnızca aşağıdaki durumlarda gerekir: İstekte willPauseWhenDucked(true) veya setAcceptsDelayedFocusGain(true).

Dinleyiciyi ayarlamak için iki yöntem vardır: birincisi olan ve olmayan işleyici bağımsız değişkenidir. İşleyici, işleyicinin üzerinde çalıştırıldığı iş parçacığıdır. Şu durumda: bir işleyici belirtmeyin; ana Looper kullanılıyor.

Aşağıdaki örnekte, derleme için AudioFocusRequest.Builder özelliğinin nasıl kullanılacağı gösterilmektedir bir AudioFocusRequest ve ses odağını isteyip iptal etmek istiyor:

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

Otomatik kısma

Android 8.0 (API düzeyi 26) sürümünde, başka bir uygulama isteği AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK sistem, sesi kısmak ve geri yüklemek için uygulamanın onAudioFocusChange() geri çağırması çağrılmadan.

Otomatik kısma, müzik ve video oynatma için kabul edilebilir bir davranış olsa da Bu özellik, konuşmalı içerik oynatırken (örneğin, sesli kitap uygulaması. Bu durumda, uygulama duraklatılmalıdır.

Uygulamanızın ses düzeyini azaltmak yerine kısması istendiğinde duraklatılmasını istiyorsanızOnAudioFocusChangeListener İstenen duraklatma/devam ettirme davranışını uygulayan bir onAudioFocusChange() geri çağırma yöntemidir. Dinleyiciyi kaydetmek için setOnAudioFocusChangeListener() numaralı telefonu arayın ve şu numarayı arayın: setWillPauseWhenDucked(true) özelliği kullanmanızı öneririz.

Gecikmeli odak kazancı

Bazı durumlarda sistem, odaklamanın odak noktası "kilitli" başka bir uygulama tarafından (örneğin, telefon görüşmesi sırasında) Böyle durumlarda requestAudioFocus(), AUDIOFOCUS_REQUEST_FAILED değerini döndürür. Böyle bir durumda, Ses çalmaya devam etmemeli çünkü odaklanacağız.

Uygulamanızın odaklanma isteğini işleme almasını sağlayan setAcceptsDelayedFocusGain(true) yöntemi eşzamansız olarak ayarlayabilirsiniz. Bu işaret ayarlandığında odak kilitliyken istek yapılır AUDIOFOCUS_REQUEST_DELAYED değerini döndürür. Sesi kilitleyen koşul görüşme sona erdiğinde sistem Beklemedeki odaklanma isteğini verir ve onAudioFocusChange() uygulamasını indirin.

Gecikmeli odak kazancını ele almak için Şu özelliklere sahip onAudioFocusChange() geri çağırma yöntemiyle OnAudioFocusChangeListener: istenen davranışı uygular ve setOnAudioFocusChangeListener().

Android 7.1 ve önceki sürümlerde ses odağı

Aradığınızda requestAudioFocus() bir süre ipucu belirtmeniz gerekiyor. o anda odaklanıp oynayan başka bir uygulama tarafından onurlandırılacaktır:

  • Ses çalmayı planladığınızda kalıcı ses odağı (AUDIOFOCUS_GAIN) isteyin yakın gelecekte de (örneğin, müzik çalarken) çalmayı durdurması için ses odağının önceki sahibine gidin.
  • Oynatmayı beklediğinizde geçici odak (AUDIOFOCUS_GAIN_TRANSIENT) iste kısa bir süre kullanılabiliyorsa ve önceki sahibinin duraklamasını bekliyorsanız çalıyor.
  • Sesi kısma ile geçici odak isteği (AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) (ses çalmayı beklediğinizi belirtir) kısa bir süre için geçerli olduğundan ve önceki odak sahibinin "ördekler" ise oynamak ses çıkışını (küçültür). İki ses çıkışı da karışık bulunur. Sesi kısma özelliği özellikle (ör. sesli yol tarifi için) aralıklı olarak ses yayını.

requestAudioFocus() yöntemi ayrıca bir AudioManager.OnAudioFocusChangeListener gerektirir. Bu işleyici medya oturumunuzun sahibi olan aynı etkinlik veya hizmette oluşturulmuş olmalıdır. Google uygulamanızınonAudioFocusChange() Başka bir uygulama, ses odağını edinir veya terk eder.

Aşağıdaki snippet, akışta kalıcı ses odağı istiyor STREAM_MUSIC ve işlenmesi için bir OnAudioFocusChangeListener kaydeder ses odağında değişiklikler olabilir. (Değişim dinleyicisi Ses odağı değişikliğine yanıt verme.)

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
}

Oynatmayı bitirdiğinizde şunu arayın: abandonAudioFocus().

Kotlin

audioManager.abandonAudioFocus(afChangeListener)

Java

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

Bu işlem, sisteme artık odaklanmaya ihtiyaç duymadığınızı bildirir ve ilişkilendirilmiş OnAudioFocusChangeListener. Geçici odak isteğinde bulunduysanız Bu işlem duraklatılan ya da kısılan bir uygulamaya oynamaya devam edebileceğini veya ses düzeyini tekrar etkinleştirebilir.

Ses odağı değişikliğine yanıt verme

Bir uygulama ses odağını edindiğinde başka bir uygulama bu odağı serbest bırakabilmeli kendisi için ses odağı istiyor. Böyle bir durumda uygulamanız bir çağrı geldiğinde onAudioFocusChange() AudioFocusChangeListener yöntemindeki Uygulama requestAudioFocus() adlı uygulamayı çağırdığında belirttiğiniz işlem.

onAudioFocusChange() öğesine iletilen focusChange parametresi, türü belirtir görme fırsatınız olur. Şuna karşılık gelir: uygulamanın kullandığı süre ipucuna bakalım. Uygulamanız yanıt verebilirler.

Geçici odak kaybı
. Odak değişikliği geçiciyse (AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK veya AUDIOFOCUS_LOSS_TRANSIENT) olduğu gibi, uygulamanız gereken otomatik kısma) veya oynatmayı duraklatarak Aksi takdirde aynı durum korunur.

Ses odağının geçici olarak kaybedilmesi durumunda değişiklikleri izlemeye devam etmelisiniz. tekrar etkinleştirdiğinizde normal çalmaya devam etmeye hazır olun. odaklanacağız. Engelleyen uygulama odağı terk ettiğinde geri arama alırsınız. (AUDIOFOCUS_GAIN). Bu noktada ses düzeyini normal düzeye geri yükleyebilirsiniz. veya oynatmayı yeniden başlatın.

Kalıcı odak kaybı
. Ses odağı kaybı kalıcıysa (AUDIOFOCUS_LOSS) başka bir uygulama Ses çalınıyor. Uygulamanız, hiçbir zaman duraklatılmayacağı için oynatmayı hemen duraklatmalıdır AUDIOFOCUS_GAIN geri aranacak. Kullanıcı, oynatmayı yeniden başlatmak için Aktarım denetimine basmak gibi açık bir işlem yapmalıdır. kullanıcı arayüzünde görebilirsiniz.

Aşağıdaki kod snippet'i, OnAudioFocusChangeListener ve onAudioFocusChange() geri araması. Dikkat edin: Kalıcı ses kaybı durumunda geri çağırmayı geciktirmek için Handler kullanılması odaklanacağız.

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

İşleyici, aşağıdakine benzer bir Runnable kullanır:

Kotlin

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

Java

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

Kullanıcı oynatmayı yeniden başlatırsa geciken durdurmanın devreye girmediğinden emin olmak için Herhangi bir duruma yanıt olarak mHandler.removeCallbacks(mDelayedStopRunnable) anlamına gelir. Örneğin, geri aramanızın onPlay() numarasından removeCallbacks() numaralı telefonu arayın. onSkipToNext() vb. Hizmetiniz tarafından kullanılan kaynaklar temizlenirken onDestroy() geri arama.