Ses odağını yönet

İki veya daha fazla Android uygulaması aynı çıkış akışına aynı anda ses oynatabilir ve sistem her şeyi birlikte karıştırır. Bu teknik açıdan etkileyici olsa da kullanıcılar için çok can sıkıcı olabilir. Android, tüm müzik uygulamalarının aynı anda çalmasını önlemek için ses odak noktası fikrini sunar. Aynı anda yalnızca bir uygulama ses odağına sahip olabilir.

Uygulamanızın ses çıkarması gerektiğinde ses odağını istemelidir. Odaklandığında ses çalabilir. Ancak ses odağını aldıktan sonra oyunu bitirinceye kadar bu özelliği koruyamayabilirsiniz. Başka bir uygulama, ses odağına sahip olmanızı engelleyecek şekilde odak isteğinde bulunabilir. Bu durumda uygulamanız, kullanıcıların yeni ses kaynağını daha kolay duyabilmesi için oynatmayı duraklatmalı veya ses seviyesini düşürmelidir.

Android 12'den (API düzeyi 31) önce ses odak noktası sistem tarafından yönetilmez. Bu nedenle, uygulama geliştiricilerin ses odak yönergelerine uymaları önerilir. Ancak bir uygulama, Android 11 (API düzeyi 30) veya önceki sürümleri çalıştıran bir cihazda ses odağını kaybettikten sonra bile yüksek sesle çalmaya devam ederse sistem bunu engelleyemez. Ancak bu uygulama davranışı, kullanıcı deneyimini olumsuz yönde etkiler ve genellikle kullanıcıların sorunlu uygulamayı kaldırmasına neden olur.

İyi tasarlanmış bir ses uygulaması, ses odağını aşağıdaki genel yönergelere göre yönetmelidir:

  • Oynamaya başlamadan hemen önce requestAudioFocus()'ü arayın ve aramanın AUDIOFOCUS_REQUEST_GRANTED numarası ile yanıtlandığını doğrulayın. Medya oturumunuzun onPlay() geri çağırma işlevinde requestAudioFocus() çağrısını yapın.

  • Başka bir uygulama ses odağını aldığında oynatmayı durdurun veya duraklatın ya da sesi kısın (yani azaltın).

  • Oynatma durduğunda (örneğin, uygulamada çalınacak bir şey kalmadığında) ses odağını bırakın. Kullanıcı oynatmayı duraklatırsa uygulamanızın ses odağını kaybetmesi gerekmez. Kullanıcı daha sonra oynatmayı devam ettirebilir.

  • Uygulamanızın çaldığı ses türünü belirtmek için AudioAttributes öğesini kullanın. Örneğin, konuşma çalan uygulamalar için CONTENT_TYPE_SPEECH değerini belirtin.

Ses odak noktası, çalıştırılan Android sürümüne bağlı olarak farklı şekilde ele alınır:

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 bir uygulamadan ses oynatmanın yavaşça sona ermesini sağlar. Sistem, gelen bir arama olduğunda ses oynatmayı da kapatır.
Android 8.0 (API düzeyi 26) ile Android 11 (API düzeyi 30) arasındaki sürümler
Ses odak noktası sistem tarafından yönetilmez ancak Android 8.0 (API düzeyi 26) sürümünden itibaren kullanıma sunulan bazı değişiklikleri içerir.
Android 7.1 (API düzeyi 25) ve önceki sürümler
Ses odağı sistem tarafından yönetilmez. Uygulamalar, requestAudioFocus() ve abandonAudioFocus() öğelerini kullanarak ses odağını yönetir.

Android 12 ve sonraki sürümlerde ses odak noktası

İşitsel odak kullanan bir medya veya oyun uygulaması, odağı kaybettikten sonra ses çalmamalıdır. Android 12 (API düzeyi 31) ve sonraki sürümlerde sistem bu davranışı zorunlu kılar. Odak başka bir uygulamadayken ve bu uygulama ses çalarken bir uygulama ses odağını istediğinde sistem, çalan uygulamanın ses seviyesini azaltır. Eklenen karartma özelliği, bir uygulamadan diğerine geçişi daha sorunsuz hale getirir.

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

  1. Şu anda oynatılan ilk uygulama aşağıdaki ölçütlerin tümünü karşılamalıdır:

  2. İkinci bir uygulama, AudioManager.AUDIOFOCUS_GAIN ile ses odağı ister.

Bu koşullar karşılandığında ses sistemi ilk uygulamanın sesini yavaşça azaltır. Ses azaltmanın sonunda sistem, ilk uygulamayı odak kaybı konusunda bilgilendirir. Uygulamanın oynatıcıları, uygulama ses odağını tekrar isteyene kadar sessiz kalır.

Mevcut ses odağı davranışları

Ses odağında geçiş içeren diğer durumlara da dikkat etmeniz gerekir.

Otomatik ses kısma

Otomatik ses azaltma (bir uygulamanın ses seviyesini geçici olarak azaltarak başka bir uygulamanın net bir şekilde duyulmasını sağlama), Android 8.0 (API düzeyi 26) sürümünde kullanıma sunulmuştur.

Sistemin ses azaltma özelliğini uygulamasını sağlayarak uygulamanızda ses azaltma özelliğini uygulamanız gerekmez.

Otomatik ses azaltma, sesli bildirim oynatılan bir uygulamadan odağı aldığında da gerçekleşir. Bildirim oynatmanın başlangıcı, ses azaltma rampasının sonuyla senkronize edilir.

Otomatik ses azaltma, aşağıdaki koşullar karşılanırsa gerçekleşir:

  1. Şu anda oynatılan ilk uygulama aşağıdaki ölçütlerin tümünü karşılamalıdır:

  2. İkinci uygulama, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK ile ses odağını ister.

Bu koşullar karşılandığında ses sistemi, ikinci uygulamanın odakta olduğu sırada ilk uygulamanın tüm etkin oynatıcılarını susturur. İkinci uygulama odaktan çıktığında, bu uygulamaların üstündeki örtü kaldırılır. İlk uygulama, odağı kaybettiğinde bilgilendirilmez. Bu nedenle, herhangi bir işlem yapması gerekmez.

Kullanıcı konuşma içeriği dinlerken otomatik ses azaltmanın yapılmadığını unutmayın. Aksi takdirde kullanıcı, programın bir kısmını kaçırabilir. Örneğin, sürüş yol tarifleri için sesli rehberlik azaltılmaz.

Gelen telefon aramaları için mevcut ses çalmayı kapatma

Bazı uygulamalar düzgün çalışmaz ve telefon görüşmeleri sırasında ses çalmaya devam eder. Bu durum, kullanıcının aramayı duymak için rahatsız edici uygulamayı bulup sessize almasını veya uygulamadan çıkmasını zorunlu kılar. Bunu önlemek için sistem, gelen bir arama sırasında diğer uygulamalardan gelen sesleri kapatabilir. Sistem, gelen bir telefon araması alındığında ve bir uygulama aşağıdaki koşulları karşıladığında bu özelliği çağırır:

  • Uygulamada AudioAttributes.USAGE_MEDIA veya AudioAttributes.USAGE_GAME kullanım özelliği var.
  • Uygulama, ses odağını (herhangi bir odak kazanımı) başarıyla istedi ve ses çalıyor.

Arama sırasında oynatmaya devam eden uygulamaların sesi, arama sona erene kadar kapatılır. Ancak arama sırasında bir uygulama oynatmaya başlarsa kullanıcının oynatmayı kasıtlı olarak başlattığı varsayılarak bu oynatıcı kapatılmaz.

Android 8.0 ile Android 11 arasındaki sürümlerde ses odak noktası

Android 8.0 (API düzeyi 26) sürümünden itibaren requestAudioFocus() işlevini çağırırken bir AudioFocusRequest parametresi sağlamanız gerekir. AudioFocusRequest, uygulamanızın ses bağlamı ve özellikleri hakkında bilgi içerir. Sistem, ses odağının kazanılmasını ve kaybedilmesini otomatik olarak yönetmek için bu bilgileri kullanır. Ses odağını bırakmak için, bağımsız değişkeni AudioFocusRequest olan abandonAudioFocusRequest() yöntemini çağırın. Hem odaklanmayı istediğinizde hem de odaklanmayı bıraktığınızda aynı AudioFocusRequest örneğini kullanın.

AudioFocusRequest oluşturmak için AudioFocusRequest.Builder kullanın. Odak isteği her zaman isteğin türünü belirtmesi gerektiğinden, tür oluşturucu için yapıcıya dahil edilir. İsteğin diğer alanlarını ayarlamak için oluşturucunun yöntemlerini kullanın.

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

YöntemNotlar
setFocusGain() Bu alan her istekte zorunludur. Android 8.0 öncesi requestAudioFocus() çağrısında kullanılan durationHint ile aynı değerleri alır: AUDIOFOCUS_GAIN, AUDIOFOCUS_GAIN_TRANSIENT, AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK veya AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE.
setAudioAttributes() AudioAttributes, uygulamanızın kullanım alanını tanımlar. Sistem, bir uygulama ses odağını kazandığında ve kaybettiğinde bu bilgilere bakar. Özellikler, yayın türü kavramının önüne geçer. 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ılmıştır. Odak isteğinde, ses oynatıcınızda kullandığınız özellikleri kullanın (bu tablonun altındaki örnekte gösterildiği gibi).

Önce özellikleri belirtmek için bir AudioAttributes.Builder kullanın, ardından bu yöntemi kullanarak özellikleri isteğe atayın.

Belirtilmezse AudioAttributes varsayılan olarak AudioAttributes.USAGE_MEDIA olur.

setWillPauseWhenDucked() Başka bir uygulama AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK ile odaklanmayı istediğinde, sistem gizlemeyi kendi başına yapabildiğinden odaklanmaya sahip uygulama genellikle bir onAudioFocusChange() geri çağırma almaz. Sesi azaltmak yerine oynatmayı duraklatmanız gerektiğinde setWillPauseWhenDucked(true) işlevini çağırın ve otomatik ses azaltma bölümünde açıklandığı gibi bir OnAudioFocusChangeListener oluşturup ayarlayın.
setAcceptsDelayedFocusGain() Odak başka bir uygulama tarafından kilitlendiğinde ses odağı isteği başarısız olabilir. Bu yöntem, gecikmeli odak kazanmayı (odak kullanıma sunulduğunda asenkron olarak odak elde etme) etkinleştirir.

Gecikmeli odağı kazanma özelliğinin yalnızca ses isteğinde bir AudioManager.OnAudioFocusChangeListener belirtmeniz durumunda çalıştığını unutmayın. Bunun nedeni, uygulamanızın odağı aldığını bilmesi için geri çağırma işlevini alması gerekmesidir.

setOnAudioFocusChangeListener() OnAudioFocusChangeListener yalnızca isteğinde willPauseWhenDucked(true) veya setAcceptsDelayedFocusGain(true) de belirtirseniz gereklidir.

Dinleyiciyi ayarlamak için iki yöntem vardır: Biri işleyici bağımsız değişkeni olan, diğeri ise işleyici bağımsız değişkeni olmayan. İşleyici, dinleyicinin çalıştığı iş parçacığıdır. Bir işleyici belirtmezseniz ana Looper ile ilişkili işleyici kullanılır.

Aşağıdaki örnekte, AudioFocusRequest oluşturmak ve ses odağını istemek ve bırakmak için AudioFocusRequest.Builder'ün nasıl kullanılacağı gösterilmektedir:

KotlinJava
// 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
        }
    }
}
// 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 ses kısma

Android 8.0'da (API düzeyi 26), başka bir uygulama AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK ile odaklanmayı istediğinde sistem, uygulamanın onAudioFocusChange() geri çağırma işlevini çağırmadan sesi kısabilir ve geri yükleyebilir.

Otomatik ses azaltma, müzik ve video oynatma uygulamaları için kabul edilebilir bir davranış olsa da sesli kitap uygulaması gibi sözlü içerik oynatırken kullanışlı değildir. Bu durumda uygulamanın duraklatması gerekir.

Uygulamanızın ses düzeyini azaltmak yerine sessiz moduna geçmesini istiyorsanız istenen duraklatma/devam ettirme davranışını uygulayan bir onAudioFocusChange() geri çağırma yöntemi içeren bir OnAudioFocusChangeListener oluşturun. Dinleyiciyi kaydetmek için setOnAudioFocusChangeListener(), sistemi otomatik ses azaltma yerine geri aramanızı kullanması için setWillPauseWhenDucked(true) işlevini çağırın.

Gecikmeli odaklanma

Bazen sistem, odak başka bir uygulama tarafından "kilitlendiği" için (ör. telefon görüşmesi sırasında) ses odağına yönelik isteği yerine getiremez. Bu durumda, requestAudioFocus() AUDIOFOCUS_REQUEST_FAILED değerini döndürür. Bu durumda, uygulamanız odak alamadığı için ses oynatmaya devam etmemelidir.

Uygulamanızın, odaklanma isteğini eşzamansız olarak işlemesine olanak tanıyan setAcceptsDelayedFocusGain(true) yöntemi. Bu işaret ayarlandığında, odak kilitliyken yapılan bir istek AUDIOFOCUS_REQUEST_DELAYED döndürür. Ses odağını kilitleyen koşul artık mevcut olmadığında (ör. telefon görüşmesi sona erdiğinde) sistem, bekleyen odak isteğini onaylar ve uygulamanızı bilgilendirmek için onAudioFocusChange() çağrısı yapar.

Odaklanma süresinin gecikmesini ele almak için, istenen davranışı uygulayan bir onAudioFocusChange() geri çağırma yöntemi içeren bir OnAudioFocusChangeListener oluşturmanız ve setOnAudioFocusChangeListener() çağrısını yaparak dinleyiciyi kaydetmeniz gerekir.

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

requestAudioFocus() işlevini çağırırken, şu anda odak noktasında olan ve oynatılan başka bir uygulama tarafından dikkate alınabilecek bir süre ipucu belirtmeniz gerekir:

  • Önümüzdeki süre boyunca ses çalmayı planladığınızda (ör. müzik çalarken) ve ses odağının önceki sahibinin çalmayı durdurmasını beklediğinizde kalıcı ses odağını (AUDIOFOCUS_GAIN) isteyin.
  • Sesi yalnızca kısa bir süre oynatmayı ve önceki sahibin oynatmayı duraklatmasını beklediğinizde geçici odak (AUDIOFOCUS_GAIN_TRANSIENT) isteyin.
  • Ses oynatmayı yalnızca kısa bir süre beklediğinizi ve önceki odak sahibinin ses çıkışını "azaltarak" (düşük sesle) oynatmaya devam etmesinin uygun olduğunu belirtmek için ses azaltma (AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) ile geçici odak isteğinde bulunun. Her iki ses çıkışı da ses akışına karıştırılır. Ses azaltma özelliği, özellikle ses akışını aralıklı olarak kullanan uygulamalar (ör. sesli yol tarifleri) için uygundur.

requestAudioFocus() yöntemi için bir AudioManager.OnAudioFocusChangeListener de gereklidir. Bu dinleyici, medya oturumunuzun sahibi olan etkinlikte veya hizmette oluşturulmalıdır. Başka bir uygulama ses odağını aldığında veya terk ettiğinde uygulamanızın aldığı geri çağırma işlevini onAudioFocusChange() uygular.

Aşağıdaki snippet, akışta kalıcı ses odak isteğinde bulunur STREAM_MUSIC ve ses odağındaki sonraki değişiklikleri işlemek için bir OnAudioFocusChangeListener kaydeder. (Değişiklik dinleyicisi, Ses odak değişikliğine yanıt verme bölümünde ele alınmıştır.)

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

Oynatma işlemini tamamladığınızda abandonAudioFocus() numaralı telefonu arayın.

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

Bu işlem, sisteme artık odaklanmaya ihtiyacınız olmadığını bildirir ve ilişkili OnAudioFocusChangeListener öğesinin kaydını siler. Geçici odaklanma isteğinde bulunduysanız duraklatılmış veya sessize alınmış bir uygulama, oynatmaya devam edebileceğini veya sesini geri yükleyebileceğini bildirir.

Ses odağındaki bir değişikliğe yanıt verme

Bir uygulama ses odağını aldığında, başka bir uygulama ses odağını kendisi için istediğinde bu odağı bırakabilmelidir. Bu durumda, uygulamanız requestAudioFocus() adlı uygulamayı çağırırken belirttiğiniz AudioFocusChangeListener sınıfındaki onAudioFocusChange() yöntemine çağrı alır.

onAudioFocusChange() parametresine iletilen focusChange parametresi, gerçekleşen değişiklik türünü belirtir. Odak alan uygulama tarafından kullanılan süre ipucuyla aynıdır. Uygulamanız uygun şekilde yanıt vermelidir.

Geçici odaklanma kaybı
Odak değişikliği geçiciyse (AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK veya AUDIOFOCUS_LOSS_TRANSIENT) uygulamanız, otomatik olarak karartma özelliğini kullanmıyorsanız karartmalı veya oynatmayı duraklatmalı ancak aksi takdirde aynı durumda kalmalıdır.

Geçici olarak ses odağını kaybetmeniz durumunda ses odağındaki değişiklikleri izlemeye devam etmeniz ve odağı tekrar kazandığınızda normal oynatmayı devam ettirmeye hazır olmanız gerekir. Engelleyen uygulama odaktan çıktığında geri çağırma alırsınız (AUDIOFOCUS_GAIN). Bu noktada sesi normal seviyeye geri getirebilir veya oynatmayı yeniden başlatabilirsiniz.

Odak kaybının kalıcı olması
Ses odak kaybı kalıcıysa (AUDIOFOCUS_LOSS) başka bir uygulama ses çalıyordur. AUDIOFOCUS_GAIN geri çağırma çağrısı almayacağından uygulamanız oynatmayı hemen duraklatmalıdır. Oynatma işlemini yeniden başlatmak için kullanıcının, bildirimde veya uygulama kullanıcı arayüzünde oynatma taşıma kontrolüne basmak gibi açık bir işlem yapması gerekir.

Aşağıdaki kod snippet'inde, OnAudioFocusChangeListener ve onAudioFocusChange() geri çağırma işlevinin nasıl uygulanacağı gösterilmektedir. Ses odağının kalıcı olarak kaybedilmesi durumunda durdurma geri çağırmasını geciktirmek için Handler kullanıldığını fark edin.

KotlinJava
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
        }
    }
}
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ğıdaki gibi bir Runnable kullanır:

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

Kullanıcı oynatmayı yeniden başlatırsa gecikmeli durdurma işleminin devreye girmemesini sağlamak için durum değişikliklerine yanıt olarak mHandler.removeCallbacks(mDelayedStopRunnable) işlevini çağırın. Örneğin, geri çağırma işlevinin onPlay(), onSkipToNext() vb. parametrelerinde removeCallbacks()'ü çağırın. Ayrıca, hizmetiniz tarafından kullanılan kaynakları temizlerken hizmetinizin onDestroy() geri çağırma işlevinde de bu yöntemi çağırmanız gerekir.