แอป Android อย่างน้อย 2 แอปเล่นเสียงไปยังสตรีมเอาต์พุตเดียวกันได้ แล้วระบบจะผสมทุกอย่างเข้าด้วยกัน ขณะที่ ในทางเทคนิคแล้ว ผู้ใช้อาจสร้างความเสียหายได้อย่างมาก เพื่อหลีกเลี่ยงทุก แอปเพลงที่เล่นในเวลาเดียวกัน Android ได้แนะนำแนวคิดเรื่องเสียง โฟกัส โฟกัสเสียงได้ครั้งละ 1 แอปเท่านั้น
เมื่อแอปต้องเอาต์พุตเสียง แอปควรขอการโฟกัสเสียง เมื่อมี ก็จะเล่นเสียงได้ แต่หลังจากที่คุณได้รับโฟกัสทางเสียงแล้ว คุณจะไม่สามารถ คุณจะเก็บเพลงไว้เล่นจนกว่าจะเล่นจบ แอปอื่นสามารถขอโฟกัสได้ ระงับการโฟกัสเสียงค้างไว้ หากเป็นเช่นนั้น แอปควรหยุดชั่วคราว เล่นหรือลดระดับเสียงเพื่อให้ผู้ใช้ได้ยินแหล่งที่มาของเสียงใหม่ได้ง่ายขึ้น
ก่อน Android 12 (API ระดับ 31) ระบบจะไม่จัดการการโฟกัสเสียง ดังนั้น ในขณะที่นักพัฒนาแอปควรปฏิบัติตามหลักเกณฑ์ที่เน้นเรื่องเสียง หากแอปยังคงเล่นเสียงดังต่อไปแม้จะไม่ได้โฟกัสเสียงในอุปกรณ์แล้ว ใช้ Android 11 (API ระดับ 30) หรือต่ำกว่า ระบบจะป้องกันไม่ได้ อย่างไรก็ตาม ลักษณะการทำงานของแอปเช่นนี้ทําให้ผู้ใช้ได้รับประสบการณ์ที่ไม่ดี และบ่อยครั้ง ผู้ใช้ถอนการติดตั้งแอปที่ทำงานผิดปกติได้
แอปเสียงที่ออกแบบมาอย่างดีควรจัดการโฟกัสของเสียงตามคำทั่วไปเหล่านี้ หลักเกณฑ์:
โทรหา
requestAudioFocus()
ทันทีก่อนที่จะเริ่มเล่นและยืนยันว่า การโทรกลับAUDIOFOCUS_REQUEST_GRANTED
โทรหาrequestAudioFocus()
ใน CallbackonPlay()
ของเซสชันสื่อของคุณเมื่อแอปอื่นได้โฟกัสเสียง ให้หยุดหรือหยุดเล่นชั่วคราว หรือเล่นเป็ด (กล่าวคือ ลดเสียง)
เมื่อการเล่นหยุด (เช่น เมื่อแอปไม่เหลือให้เล่นแล้ว) ยกเลิกโฟกัสเสียง ทำให้แอปไม่ต้องยกเลิกการโฟกัสเสียงหากผู้ใช้ หยุดการเล่นชั่วคราวแต่อาจกลับมาเล่นอีกครั้งในภายหลัง
ใช้
AudioAttributes
เพื่ออธิบาย ประเภทเสียงที่แอปของคุณกำลังเล่น เช่น สำหรับแอปที่อ่านออกเสียง ระบุCONTENT_TYPE_SPEECH
การโฟกัสเสียงจะได้รับการจัดการแตกต่างกันไปตามเวอร์ชันของ Android กำลังทำงาน:
- Android 12 (API ระดับ 31) ขึ้นไป
- การโฟกัสเสียงจัดการโดยระบบ ระบบจะบังคับให้เล่นเสียงจาก แอปที่จะค่อยๆ เบาลงเมื่ออีกแอปหนึ่งขอโฟกัสเสียง ระบบ ปิดเสียงการเล่นเสียงเมื่อมีสายเรียกเข้าได้ด้วย
- Android 8.0 (API ระดับ 26) ถึง Android 11 (API ระดับ 30)
- ระบบไม่ได้จัดการการโฟกัสเสียง แต่มีการเปลี่ยนแปลงบางอย่าง เปิดตัวใน Android 8.0 (API ระดับ 26)
- Android 7.1 (API ระดับ 25) และต่ำกว่า
- ระบบไม่ได้จัดการโฟกัสเสียง และแอปจัดการโฟกัสเสียงโดยใช้
requestAudioFocus()
และabandonAudioFocus()
โฟกัสเสียงใน Android 12 ขึ้นไป
แอปสื่อหรือแอปเกมที่ใช้การโฟกัสเสียงไม่ควรเล่นเสียงหลังจากที่แอปหายไป โฟกัส ใน Android 12 (API ระดับ 31) ขึ้นไป ระบบจะบังคับใช้ พฤติกรรมของคุณ เมื่อแอปขอโฟกัสเสียงในขณะที่อีกแอปหนึ่งมีการโฟกัสและ กำลังเล่นอยู่ ระบบจะบังคับให้แอปที่กำลังเล่นจางลง นอกจากนี้ การค่อยๆ เบาลงจะช่วยให้การเปลี่ยนภาพจากแอปหนึ่งไปยังอีกแอปหนึ่งราบรื่นขึ้น
ลักษณะการค่อยๆ เบาลงนี้จะเกิดขึ้นเมื่อเป็นไปตามเงื่อนไขต่อไปนี้
แอปแรกที่กำลังเล่นอยู่ตรงตามเกณฑ์ต่อไปนี้ทั้งหมด
- แอปมี
AudioAttributes.USAGE_MEDIA
หรือ แอตทริบิวต์การใช้งานAudioAttributes.USAGE_GAME
- แอปขอโฟกัสเสียงด้วย
AudioManager.AUDIOFOCUS_GAIN
เรียบร้อยแล้ว - แอปไม่ได้เล่นเสียงที่มีประเภทเนื้อหา
AudioAttributes.CONTENT_TYPE_SPEECH
- แอปมี
แอปที่ 2 ขอโฟกัสเสียงด้วย
AudioManager.AUDIOFOCUS_GAIN
เมื่อมีคุณสมบัติตรงตามเงื่อนไขเหล่านี้ ระบบเสียงจะค่อยๆ เบาลงในแอปแรก ที่ การค่อยๆ เลือนหายไป ระบบจะแจ้งเตือนแอปแรกที่สูญเสียโฟกัส แอป โปรแกรมเล่นจะปิดเสียงจนกว่าแอปจะขอโฟกัสเสียงอีกครั้ง
ลักษณะการทำงานของการโฟกัสเสียงที่มีอยู่
คุณควรทราบกรณีอื่นๆ ที่เกี่ยวข้องกับการเปลี่ยนเสียงด้วย โฟกัส
การลดเสียงอัตโนมัติ
การลดเสียงโดยอัตโนมัติ (ลดระดับเสียงของแอป 1 รายการชั่วคราวเพื่อให้ อีกอย่างหนึ่งอาจมีอย่างชัดเจน) ได้รับการนำมาใช้ใน Android 8.0 (API ระดับ 26)
การมีระบบที่จะนำการลดเสียงมาใช้ช่วยให้คุณไม่ต้องดำเนินการแก้ปัญหาใดๆ แอปของคุณ
การลดเสียงโดยอัตโนมัติยังเกิดขึ้นเมื่อเสียงการแจ้งเตือนจับโฟกัส จากแอปที่กำลังเล่นอยู่ ซิงค์การเริ่มเล่นการแจ้งเตือนแล้ว ด้วยการสิ้นสุดของทางลาด
การลดอัตโนมัติจะเกิดขึ้นเมื่อเป็นไปตามเงื่อนไขต่อไปนี้
แอปแรกที่กำลังเล่นอยู่เป็นไปตามเกณฑ์ต่อไปนี้ทั้งหมด
- แอปขอโฟกัสเสียงกับโฟกัสทุกประเภทสำเร็จ ได้รับ
- แอปไม่เล่นเสียงตามประเภทเนื้อหา
AudioAttributes.CONTENT_TYPE_SPEECH
- แอปไม่ได้ตั้งค่า
AudioFocusRequest.Builder.setWillPauseWhenDucked(true)
แอปที่ 2 ขอโฟกัสเสียงด้วย
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
เมื่อมีคุณสมบัติตรงตามเงื่อนไขเหล่านี้ ระบบเสียงจะตัดโปรแกรมเล่นที่ใช้งานอยู่ทั้งหมดของ แอปแรกในขณะที่แอปที่สองมีสมาธิ เมื่อแอปที่สองยกเลิกการทำงาน มันจะทำให้พวกเขาไม่โฟกัส แอปแรกจะไม่ได้รับการแจ้งเตือนเมื่อโฟกัสหายไป โมเดลนี้จึงไม่ต้องดำเนินการใดๆ
โปรดทราบว่าการลดเสียงอัตโนมัติจะไม่ทำงานเมื่อผู้ใช้กำลังฟัง เนื้อหาเสียงพูด เนื่องจากผู้ใช้อาจพลาดบางโปรแกรมไป ตัวอย่างเช่น การนำทางด้วยเสียงสำหรับเส้นทางการขับขี่ไม่ได้หายไป
ปิดเสียงปัจจุบันสำหรับสายเรียกเข้า
แอปบางแอปทำงานไม่ถูกต้องและเล่นเสียงต่อในระหว่างการโทร สถานการณ์นี้จะบังคับให้ผู้ใช้ค้นหาและปิดเสียงหรือออกจากแอปที่ไม่เหมาะสมใน เพื่อฟังการสนทนา เพื่อป้องกันปัญหานี้ ระบบจะปิดเสียงจาก ขณะมีสายเข้า ระบบจะเรียกใช้ฟีเจอร์นี้เมื่อ มีการรับสายเรียกเข้าและแอปมีคุณสมบัติตรงตามเงื่อนไขต่อไปนี้
- แอปมี
AudioAttributes.USAGE_MEDIA
หรือ แอตทริบิวต์การใช้งานAudioAttributes.USAGE_GAME
- แอปขอโฟกัสเสียง (การได้โฟกัสทั้งหมด) สำเร็จและกำลังเล่นอยู่ เสียง
หากแอปยังคงเล่นต่อในระหว่างการโทร การเล่นจะถูกปิดเสียงจนกว่า วางสาย อย่างไรก็ตาม หากแอปเริ่มเล่นระหว่างการโทร โปรแกรมเล่นจะไม่ ปิดเสียง โดยสันนิษฐานว่าผู้ใช้เริ่มเล่นโดยตั้งใจ
โฟกัสเสียงใน Android 8.0 ถึง Android 11
เริ่มตั้งแต่ Android 8.0 (API ระดับ 26) เป็นต้นไป เมื่อคุณเรียกใช้
requestAudioFocus()
คุณต้องระบุพารามิเตอร์ AudioFocusRequest
AudioFocusRequest
มีข้อมูลเกี่ยวกับบริบทและความสามารถของเสียงของแอป
ระบบใช้ข้อมูลนี้เพื่อจัดการการเพิ่มและการสูญเสียโฟกัสของเสียง
โดยอัตโนมัติ หากต้องการปล่อยโฟกัสเสียง ให้เรียกใช้เมธอด
abandonAudioFocusRequest()
ซึ่งต้องใช้ AudioFocusRequest
เป็นอาร์กิวเมนต์ด้วย ใช้
AudioFocusRequest
อินสแตนซ์ทั้งเมื่อคุณขอและยกเลิกการโฟกัส
หากต้องการสร้างAudioFocusRequest
ให้ใช้
AudioFocusRequest.Builder
เนื่องจากคำขอโฟกัสจะต้อง
ระบุประเภทของคำขอเสมอ ประเภทจะรวมอยู่ในตัวสร้าง
สำหรับเครื่องมือสร้าง ใช้วิธีของเครื่องมือสร้างเพื่อตั้งค่าฟิลด์อื่นๆ ของฟิลด์
อีกครั้ง
ต้องกรอกข้อมูลในช่อง FocusGain
ฟิลด์อื่นๆ ทั้งหมดเป็นตัวเลือก
วิธีการ | หมายเหตุ |
---|---|
setFocusGain()
|
ต้องระบุฟิลด์นี้ในทุกคำขอ ซึ่งจะใช้ค่าเดียวกับ
durationHint ที่ใช้ในการโทรก่อน Android 8.0 ไปยัง requestAudioFocus() :
AUDIOFOCUS_GAIN AUDIOFOCUS_GAIN_TRANSIENT
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK หรือ AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
|
setAudioAttributes()
|
AudioAttributes อธิบายกรณีการใช้งานแอปของคุณ
ระบบจะตรวจจับเสียงเหล่านั้นเมื่อแอปเพิ่มและไม่โฟกัสเสียง ลักษณะ
จะมาแทนที่หัวข้อเรื่องประเภทสตรีม ใน Android 8.0 (API ระดับ 26) ขึ้นไป
ประเภทสตรีมสำหรับการดำเนินการอื่นๆ นอกเหนือจากการควบคุมระดับเสียงเลิกใช้งานแล้ว ใช้
แอตทริบิวต์เดียวกันกับในคำขอโฟกัสที่คุณใช้ในโปรแกรมเล่นเสียง (เช่น
ที่แสดงในตัวอย่างถัดจากตารางนี้)
ใช้
หากไม่ได้ระบุไว้ |
setWillPauseWhenDucked()
|
เมื่อแอปอื่นขอให้โฟกัสด้วย
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK แอปที่มีโฟกัสไม่
มักจะได้รับ
วันที่ onAudioFocusChange()
Callback เนื่องจากระบบสามารถดำเนินการ
ลดตัวเองได้ เมื่อคุณต้องการหยุดเล่นชั่วคราว
ลดเสียงลง โทรหา setWillPauseWhenDucked(true) เพื่อสร้างและตั้งค่า
OnAudioFocusChangeListener ตามที่อธิบายไว้ในอัตโนมัติ
การลดการใช้งาน
|
setAcceptsDelayedFocusGain()
|
คำขอโฟกัสเสียงอาจล้มเหลวเมื่อโฟกัสถูกล็อกโดยแอปอื่น
วิธีนี้เปิดใช้การได้โฟกัสแบบหน่วงเวลา: ความสามารถ
เพื่อให้ได้รับโฟกัสแบบไม่พร้อมกันเมื่อพร้อมใช้งาน
โปรดทราบว่าการรับโฟกัสแบบหน่วงเวลาจะใช้ได้ต่อเมื่อคุณระบุ
|
setOnAudioFocusChangeListener()
|
คุณต้องระบุ OnAudioFocusChangeListener ในกรณีที่คุณระบุด้วยเท่านั้น
willPauseWhenDucked(true) หรือ setAcceptsDelayedFocusGain(true) ในคำขอ
การตั้งค่าผู้ฟังมี 2 วิธี ได้แก่ วิธีหนึ่งแบบมีและไม่มี
อาร์กิวเมนต์ของเครื่องจัดการ เครื่องจัดการคือเทรดที่ Listener ทำงาน หากคุณ
ไม่ระบุเครื่องจัดการ แต่เครื่องจัดการที่เชื่อมโยงกับ
ใช้งาน |
ตัวอย่างต่อไปนี้จะแสดงวิธีใช้ AudioFocusRequest.Builder
เพื่อสร้าง
AudioFocusRequest
แล้วส่งคำขอและยกเลิกการโฟกัสเสียง:
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; } } }
การลดเสียงอัตโนมัติ
ใน Android 8.0 (API ระดับ 26) เมื่อแอปอื่นขอโฟกัสด้วย
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
ระบบจะลดและคืนค่าระดับเสียงได้
โดยไม่ต้องเรียกใช้ Callback onAudioFocusChange()
ของแอป
ขณะที่การลดเสียงอัตโนมัติเป็นลักษณะการทำงานที่ยอมรับได้สำหรับการเล่นเพลงและวิดีโอ แอป ฟีเจอร์นี้จะไม่เป็นประโยชน์เมื่อเล่นเนื้อหาที่พูด เช่น แอปหนังสือเสียง ในกรณีนี้ แอปควรหยุดชั่วคราวแทน
หากคุณต้องการให้แอปหยุดชั่วคราวเมื่อระบบขอให้ลดเสียงแทนที่จะลดระดับเสียง ให้สร้าง OnAudioFocusChangeListener
ด้วย
เมธอด onAudioFocusChange()
ของ Callback ที่ใช้ลักษณะการหยุดชั่วคราว/กลับมาทำงานอีกครั้งที่ต้องการ
โทร setOnAudioFocusChangeListener()
เพื่อลงทะเบียน Listener และโทร
setWillPauseWhenDucked(true)
เพื่อบอกระบบให้ใช้ Callback แทนการลดโดยอัตโนมัติ
เพิ่มโฟกัสแบบหน่วงเวลา
บางครั้งระบบไม่สามารถให้สิทธิ์กับคำขอโฟกัสเสียงได้เนื่องจากโฟกัสอยู่ที่
"ล็อก" แอปอื่น เช่น ระหว่างการโทร ในกรณีนี้
requestAudioFocus()
แสดงผล AUDIOFOCUS_REQUEST_FAILED
เมื่อเกิดเหตุการณ์นี้ขึ้น
แอปของคุณไม่ควรเล่นเสียงต่อเนื่องจากไม่ได้รับ
โฟกัส
เมธอด setAcceptsDelayedFocusGain(true)
ซึ่งช่วยให้แอปของคุณจัดการคำขอโฟกัสได้
แบบไม่พร้อมกัน เมื่อตั้งค่าธงนี้แล้ว ระบบจะส่งคำขอเมื่อโฟกัสล็อกอยู่
แสดงผล AUDIOFOCUS_REQUEST_DELAYED
เมื่อเงื่อนไขที่ล็อกเสียง
โฟกัสไม่ได้อีกต่อไป เช่น เมื่อการโทรศัพท์สิ้นสุดลง
อนุมัติคำขอโฟกัสที่รออนุมัติ และเรียกใช้ onAudioFocusChange()
เพื่อแจ้ง
แอป
ในการจัดการการโฟกัสที่ล่าช้า คุณต้องสร้าง
OnAudioFocusChangeListener
ที่มีเมธอด Callback onAudioFocusChange()
ที่
นำพฤติกรรมที่ต้องการไปใช้และลงทะเบียน Listener โดยการเรียกใช้
setOnAudioFocusChangeListener()
โฟกัสเสียงใน Android 7.1 และต่ำกว่า
เมื่อคุณโทร
requestAudioFocus()
คุณต้องระบุคำแนะนำระยะเวลา ซึ่งอาจ
ได้รับการยกย่องจากแอปอื่นที่กำลังมีสมาธิอยู่กับการเล่น:
- ขอโฟกัสเสียงถาวร (
AUDIOFOCUS_GAIN
) เมื่อคุณวางแผนที่จะเล่นเสียง สำหรับอนาคตอันใกล้ (เช่น เมื่อเล่นเพลง) และคาดหวังว่า ที่ยึดโฟกัสเสียงก่อนหน้าเพื่อหยุดเล่น - ขอโฟกัสชั่วคราว (
AUDIOFOCUS_GAIN_TRANSIENT
) เมื่อคุณคาดว่าจะเล่น เสียงในช่วงเวลาสั้นๆ และคุณคาดว่าเจ้าของคนก่อนหน้าจะหยุดชั่วคราว กำลังเล่น - ขอโฟกัสชั่วคราวด้วยการลด
(
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
) เพื่อระบุว่าคุณคาดว่าจะเล่นเสียง ในช่วงเวลาสั้นๆ และเจ้าของโฟกัสคนก่อนหน้าเก็บเอาไว้ได้ กำลังเล่นหากเป็น "เป็ด" (ลด) เอาต์พุตเสียง เอาต์พุตเสียงทั้ง 2 แบบผสมกัน ไปยังสตรีมเสียง การลดเสียงเหมาะอย่างยิ่งสำหรับแอปที่ใช้ เสียงขาดๆ หายๆ เช่น เมื่อมีเสียงเส้นทางการขับขี่
เมธอด requestAudioFocus()
ต้องใช้ AudioManager.OnAudioFocusChangeListener
ด้วย Listener นี้ควร
ที่สร้างในกิจกรรมหรือบริการเดียวกับที่เป็นเจ้าของเซสชันสื่อของคุณ ทั้งนี้
ใช้ Callback onAudioFocusChange()
ที่แอปของคุณได้รับเมื่อ
บางแอปได้ผู้ใช้ใหม่หรือเลิกใช้การโฟกัสเสียง
ข้อมูลโค้ดต่อไปนี้ขอให้สตรีมมีเสียงแบบถาวร
STREAM_MUSIC
และลงทะเบียน OnAudioFocusChangeListener
เพื่อจัดการ
การเปลี่ยนแปลงด้านโฟกัสของเสียงที่ตามมา (จะมีการพูดคุยกันเกี่ยวกับ Listener การเปลี่ยนแปลง
การตอบสนองต่อการเปลี่ยนโฟกัสเสียง)
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 }
เมื่อเล่นเสร็จ ให้โทร
abandonAudioFocus()
Kotlin
audioManager.abandonAudioFocus(afChangeListener)
Java
// Abandon audio focus when playback complete audioManager.abandonAudioFocus(afChangeListener);
การดำเนินการนี้จะแจ้งให้ระบบทราบว่าคุณไม่ต้องโฟกัสอีกต่อไปและยกเลิกการลงทะเบียน
OnAudioFocusChangeListener
ที่เกี่ยวข้อง ถ้าคุณขอโฟกัสชั่วคราว
การดำเนินการนี้จะแจ้งเตือนแอปที่หยุดชั่วคราวหรือปิดไปแล้วว่าแอปอาจเล่นต่อไปหรือ
เพื่อคืนค่าระดับเสียง
การตอบสนองต่อการเปลี่ยนการโฟกัสเสียง
เมื่อแอปได้รับโฟกัสเสียง แอปจะต้องปล่อยได้เมื่อแอปอื่น
ขอโฟกัสเสียงเอง ในกรณีนี้ แอปของคุณ
รับสายที่โทรไปยัง
onAudioFocusChange()
ใน AudioFocusChangeListener
ที่คุณระบุเมื่อแอปชื่อว่า requestAudioFocus()
พารามิเตอร์ focusChange
ที่ส่งผ่านไปยัง onAudioFocusChange()
จะระบุชนิด
การเปลี่ยนแปลงที่กำลังเกิดขึ้น ซึ่งตรงกับ
กับคำแนะนำระยะเวลาที่ใช้โดยแอปที่กำลังโฟกัส แอปของคุณควร
ตอบสนองอย่างเหมาะสม
- สูญเสียโฟกัสชั่วคราว
-
หากการเปลี่ยนโฟกัสเป็นแบบชั่วคราว (
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
หรือAUDIOFOCUS_LOSS_TRANSIENT
) แอปของคุณก็ควรเป็นช่องโหว่ (หากคุณไม่ได้พึ่งพา ในการลดเสียงอัตโนมัติ) หรือหยุดเล่นชั่วคราวแต่ ไม่เช่นนั้น ให้คงสถานะเดิมไว้ในระหว่างที่สูญเสียโฟกัสเสียงชั่วคราว คุณควรตรวจสอบการเปลี่ยนแปลงต่อไป โฟกัสเสียงและเตรียมตัวกลับมาเล่นแบบปกติเมื่อคุณกลับมาเล่น โฟกัส เมื่อแอปที่บล็อกเลิกโฟกัส คุณจะได้รับ Callback (
AUDIOFOCUS_GAIN
) ณ จุดนี้ คุณสามารถคืนค่าระดับเสียงเป็นระดับปกติได้ หรือเริ่มเล่นใหม่ - สูญเสียโฟกัสถาวร
-
หากการสูญเสียโฟกัสเสียงเป็นแบบถาวร (
AUDIOFOCUS_LOSS
) แอปอื่น กำลังเล่นเสียง แอปของคุณควรหยุดเล่นชั่วคราวทันที เนื่องจากจะไม่เกิดขึ้น ได้รับการติดต่อกลับจากAUDIOFOCUS_GAIN
หากต้องการเริ่มเล่นอีกครั้ง ผู้ใช้ ต้องดำเนินการอย่างชัดเจน เช่น กดปุ่มควบคุมการส่งเล่น ในการแจ้งเตือนหรือ UI ของแอป
ข้อมูลโค้ดต่อไปนี้แสดงวิธีนำแท็ก
OnAudioFocusChangeListener
และ onAudioFocusChange()
ของ Callback โปรดสังเกต
ใช้ Handler
เพื่อชะลอการเรียกกลับเมื่อสูญเสียเสียงอย่างถาวร
โฟกัส
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 } } };
เครื่องจัดการจะใช้ Runnable
ซึ่งมีลักษณะดังนี้
Kotlin
private var delayedStopRunnable = Runnable { mediaController.transportControls.stop() }
Java
private Runnable delayedStopRunnable = new Runnable() { @Override public void run() { getMediaController().getTransportControls().stop(); } };
เพื่อให้มั่นใจว่าการหยุดแบบล่าช้าจะไม่เริ่มขึ้นหากผู้ใช้เริ่มเล่นอีกครั้ง โปรดโทร
mHandler.removeCallbacks(mDelayedStopRunnable)
เพื่อตอบสนองต่อสถานะใดๆ
การเปลี่ยนแปลง ตัวอย่างเช่น โทรหา removeCallbacks()
ใน onPlay()
ของ Callback
onSkipToNext()
ฯลฯ คุณควรเรียกใช้เมธอดนี้ในบริการของ
onDestroy()
Callback เมื่อล้างทรัพยากรที่บริการของคุณใช้