MediaSession เป็นส่วนประกอบของเฟรมเวิร์ก Android สำหรับจัดการการเล่นเนื้อหาสื่อและผสานรวมกับอุปกรณ์ภายนอก โดยมีอินเทอร์เฟซแบบรวมสำหรับการโต้ตอบกับชุดหูฟัง Bluetooth หูฟัง Android Auto และศูนย์สื่อของระบบ ตาม Android Developers Guide, 2026 MediaSession แทนที่ RemoteControlClient ที่เลิกใช้แล้ว และจำเป็นสำหรับเครื่องเล่นที่ซิงค์กับระบบ
ประเด็นสำคัญ
MediaSession เป็นส่วนประกอบของระบบใน Android ที่ช่วยให้แอปสามารถประกาศกิจกรรมสื่อของตนและรับคำสั่งควบคุมจากแหล่งภายนอก เมื่อผู้ใช้กดปุ่มเล่นบนชุดหูฟัง Bluetooth ระบบจะส่งเหตุการณ์นี้ไปยัง MediaSession ที่ทำงานอยู่ และแอปจะตอบสนองผ่าน Callback ของมัน
ก่อน Android 5.0 มีการใช้ RemoteControlClient เพื่อจุดประสงค์นี้ แต่มันไม่มีความยืดหยุ่นเพียงพอและไม่รองรับสถานการณ์สมัยใหม่อย่าง Android Auto นาฬิกาอัจฉริยะ และลำโพงอัจฉริยะ MediaSession ถูกนำมาใช้ใน API 21 และกลายเป็นมาตรฐานโดยพฤตินัยสำหรับแอป Android ทั้งหมดที่มีการเล่นเสียงและวิดีโอ
ตามเอกสารสำหรับนักพัฒนา Android (2026) แอปควรสร้าง MediaSession หนึ่งอันสำหรับแต่ละแหล่งการเล่นอิสระ ในเวลาใดก็ตามจะมีเพียงเซสชันเดียวที่ทำงานอยู่ — เซสชันใหม่ใดๆ จะปิดการใช้งานเซสชันก่อนหน้าโดยอัตโนมัติ
การรวม MediaSession กับ MediaBrowserService ให้วงจรการจัดการสื่อที่สมบูรณ์: บริการให้แผนผังเนื้อหา (เพลย์ลิสต์ แคตตาล็อก) และเซสชันรับคำสั่งการนำทางและการเล่น นี่คือสถาปัตยกรรมที่ Google แนะนำสำหรับเครื่องเล่นเพลง พอดแคสต์ และหนังสือเสียง
MediaBrowserService ทำงานเป็นบริการเบื้องหน้าพร้อมการแจ้งเตือน เพื่อให้แน่ใจว่าแอปยังคงทำงานต่อไปแม้ Activity จะถูกทำลาย นี่เป็นสิ่งสำคัญสำหรับเครื่องเล่นเสียงที่ต้องเล่นต่อไปเมื่อแอปถูกย่อ
เซสชันรองรับการโต้ตอบสองประเภท: รับคำสั่งจาก MediaController (ฝั่งไคลเอ็นต์) และเผยแพร่สถานะผ่าน PlaybackState MediaController สามารถอยู่ในกระบวนการเดียวกันหรือในแอปแยกต่างหาก — ระบบจะกำหนดเส้นทางคำขอผ่าน SessionToken
เมื่อผู้ใช้เรียกผู้ช่วยเสียง Android และพูดว่า “เล่นแทร็กถัดไป” ระบบจะพบ MediaSession ที่ทำงานอยู่ผ่านการเชื่อมต่อไปยัง MediaBrowserService และส่งคำสั่ง ACTION_SKIP_TO_NEXT Callback ของแอปได้รับการเรียก onSkipToNext() และอัปเดต PlaybackState
การอัปเดต PlaybackState ผ่าน setPlaybackState() จะแจ้งไปยังอินสแตนซ์ MediaController ที่เชื่อมต่อทั้งหมดทันที ศูนย์สื่อของระบบ อุปกรณ์ Bluetooth และ Android Auto ได้รับการอัปเดตพร้อมกัน — ความล่าช้าไม่เกิน 50 ms ภายใต้สภาวะปกติ
PlaybackState มีแฟลกสถานะสำคัญ: isPlaying ตำแหน่ง ความเร็ว การดำเนินการที่มี (เล่น หยุดชั่วคราว ค้นหา หยุด) หากไม่มี PlaybackState ที่กรอกอย่างถูกต้อง ระบบจะไม่รู้ว่าแอปสนับสนุนคำสั่งใดและจะไม่ส่งเหตุการณ์ที่เกี่ยวข้อง
ข้อมูลเมตา (MediaMetadata) เสริมสถานะด้วยข้อมูลเกี่ยวกับแทร็กปัจจุบัน — ชื่อเรื่อง ศิลปิน URI ปกอัลบั้ม Android Auto และอุปกรณ์สวมใส่ใช้ MediaMetadata เพื่อแสดงข้อมูลบนหน้าจอ ตาม Google I/O 2024 การกรอก MediaMetadata อย่างถูกต้องจะเพิ่มการมองเห็นแอปในโปรแกรมเรียกใช้ของบุคคลที่สามได้ถึง 40%
สถาปัตยกรรม MediaSession ประกอบด้วยสี่ส่วนประกอบที่เชื่อมต่อกัน โดยแต่ละส่วนมีบทบาทของตัวเอง นักพัฒนาต้องใช้งานทั้งสี่ส่วนเพื่อการผสานรวมกับระบบอย่างสมบูรณ์
เซสชันถูกสร้างขึ้นในเมธอด onCreate ของบริการหรือ Activity โดยเรียก MediaSessionCompat(context, tag) หลังจากสร้างแล้ว ต้องเรียก setFlags(FLAG_HANDLES_MEDIA_BUTTONS | FLAG_HANDLES_TRANSPORT_CONTROLS) ใน onDestroy จะเรียก release() เพื่อปลดปล่อยทรัพยากรระบบ
การจัดการวงจรชีวิตที่ไม่ถูกต้องเป็นหนึ่งในข้อผิดพลาดที่พบบ่อย หากไม่เรียก release() เซสชันจะยังคงอยู่ในระบบ และแอปถัดไปอาจได้รับสถานะที่ล้าสมัย Android 13+ จะแสดงคำเตือน Logcat เมื่อมีการรั่วไหลของเซสชัน
การผสานรวมพื้นฐานเริ่มต้นด้วยการสร้างเซสชันและการใช้งาน Callback แนะนำให้ใช้ MediaSessionCompat จากไลบรารี AndroidX media ซึ่งให้ API แบบรวมสำหรับ Android ทุกรุ่นตั้งแต่ API 14 ถึง 35
class MusicService : Service() {
private lateinit var mediaSession: MediaSessionCompat
private lateinit var stateBuilder: PlaybackStateCompat.Builder
override fun onCreate() {
super.onCreate()
mediaSession = MediaSessionCompat(this, "MusicService")
mediaSession.setFlags(
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
)
mediaSession.setCallback(MediaSessionCallback())
updatePlaybackState(false)
}
private inner class MediaSessionCallback : MediaSessionCompat.Callback() {
override fun onPlay() {
updatePlaybackState(true)
}
override fun onPause() {
updatePlaybackState(false)
}
}
private fun updatePlaybackState(isPlaying: Boolean) {
stateBuilder = PlaybackStateCompat.Builder()
.setState(
if (isPlaying) PlaybackStateCompat.STATE_PLAYING
else PlaybackStateCompat.STATE_PAUSED,
AudioTrackCompat.CURRENT_POSITION_NOT_SET,
1.0f
)
.setActions(
PlaybackStateCompat.ACTION_PLAY
or PlaybackStateCompat.ACTION_PAUSE
or PlaybackStateCompat.ACTION_SKIP_TO_NEXT
or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
)
mediaSession.setPlaybackState(stateBuilder.build())
}
override fun onDestroy() {
mediaSession.release()
super.onDestroy()
}
}
ในตัวอย่างนี้ มีการสร้าง MediaSession ด้วยแท็ก MusicService และแฟลกสำหรับจัดการปุ่มสื่อ Callback ใช้งาน onPlay และ onPause อัปเดต PlaybackState เมธอด setActions ประกาศการดำเนินการที่มีซึ่งระบบแสดงบนหน้าจอล็อกและในศูนย์สื่อ
private fun setMetadata(title: String, artist: String) {
val metadata = MediaMetadataCompat.Builder()
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, title)
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist)
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, 300000L)
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, albumArtUrl)
.build()
mediaSession.setMetadata(metadata)
}
ควรอัปเดตข้อมูลเมตาเมื่อมีการเปลี่ยนแทร็กแต่ละครั้ง ระบบใช้ METADATA_KEY_TITLE และ METADATA_KEY_ARTIST เพื่อแสดงข้อมูลบนจอ Bluetooth ของรถยนต์และอุปกรณ์สวมใส่ หากไม่ได้ตั้งค่า URI ปก เครื่องเล่นจะแสดงพื้นที่ว่างสีเทา
ชุดหูฟัง Bluetooth ส่งคำสั่งผ่านโปรไฟล์ AVRCP 1.6+ Android เผยแพร่คำสั่งเหล่านี้เป็นอินเทนต์ ACTION_MEDIA_BUTTON ซึ่งถูกสกัดกั้นโดย MediaSession เมื่อตั้งค่าแฟลก FLAG_HANDLES_MEDIA_BUTTONS
เมื่อผู้ใช้กดปุ่มเล่นบนหูฟัง Bluetooth ระบบจะสร้าง KeyEvent ด้วยรหัส KEYCODE_MEDIA_PLAY ซึ่งถูกส่งไปยังเมธอด onMediaButtonEvent ของ Callback หากมีการใช้งาน onPlay() ใน Callback ระบบจะเรียกโดยตรง การกดปุ่มหูฟังครั้งเดียวจะส่ง KEYCODE_MEDIA_PLAY_PAUSE — เครื่องเล่นควรสลับสถานะ
หูฟัง Bluetooth สมัยใหม่อาจมีมากถึง 5 ปุ่ม: ระดับเสียง +/-, เล่น/หยุดชั่วคราว, ถัดไป, ก่อนหน้า แต่ละปุ่มสร้าง KeyEvent ของตัวเอง ซึ่งต้องได้รับการจัดการอย่างถูกต้องโดย Callback การกด play/pause สองครั้งมักถูกตีความว่าเป็นการข้ามไปยังแทร็กถัดไป (ACTION_SKIP_TO_NEXT) ในหูฟังหลายรุ่น
ตามเอกสารคำจำกัดความความเข้ากันได้ของ Android (2026) แอปทั้งหมดที่มีเนื้อหาสื่อต้องจัดการ KEYCODE_MEDIA_PLAY_PAUSE อย่างถูกต้อง การละเว้นข้อกำหนดนี้ทำให้คะแนนแอปใน Google Play ลดลงโดยอัตโนมัติสำหรับหมวดหมู่เพลงและเสียง
ตั้งแต่ Android 11 เป็นต้นไป ศูนย์สื่อของระบบ (แผงควบคุมสื่อ) จะแสดงเซสชัน MediaSession ล่าสุดสูงสุด 5 เซสชัน ในแผงการแจ้งเตือน ผู้ใช้สามารถควบคุมเครื่องเล่นได้โดยไม่ต้องเปิดแอป สำหรับการแสดงผลที่ถูกต้อง จำเป็นต้องใช้งาน MediaBrowserService และกรอก PlaybackState อย่างถูกต้อง
แผงควบคุมสื่อแสดง: ชื่อแทร็ก ศิลปิน ปก (จาก MediaMetadata) ปุ่มควบคุม (จากการดำเนินการที่มีของ PlaybackState) หากแอปไม่อัปเดต PlaybackState อย่างน้อยทุก 10 วินาทีระหว่างการเล่นที่ทำงานอยู่ ศูนย์สื่อจะซ่อนเซสชันจากแผง
private fun startForegroundService() {
val notification = NotificationCompat.Builder(this, "media_channel")
.setSmallIcon(R.drawable.ic_play)
.setContentTitle("กำลังเล่น")
.setContentText(currentTrackTitle)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setStyle(
androidx.media.app.NotificationCompat.MediaStyle()
.setMediaSession(mediaSession.sessionToken)
)
.build()
startForeground(1001, notification)
}
การแจ้งเตือนแบบ MediaStyle เชื่อมต่อกับ MediaSession ผ่าน sessionToken และแสดงปุ่มสื่อมาตรฐาน หากไม่มี MediaStyle การแจ้งเตือนจะปรากฏเป็นการแจ้งเตือนปกติโดยไม่มีปุ่มควบคุม Android 13+ ต้องได้รับสิทธิ์ POST_NOTIFICATIONS อย่างชัดเจนสำหรับการแสดงผล
คำถามที่พบบ่อย
ในทางเทคนิคได้ แต่ในเวลาใดก็ตามจะมีเพียงเซสชันเดียวที่ถือว่า ทำงานอยู่ เมื่อสร้างเซสชันใหม่โดยไม่เรียก setActive(true) เซสชันก่อนหน้าจะยังคงทำงานอยู่ แนะนำให้มีหนึ่งเซสชันต่อแอปหรือหนึ่งเซสชันต่อแหล่งเสียงอิสระพร้อมการสลับสถานะทำงาน
MediaSession ไม่จัดการ Audio Focus โดยอัตโนมัติ — นี่เป็นกลไกแยกต่างหาก เมื่อได้รับคำสั่ง onPlay นักพัฒนาต้องขอ AudioFocus ผ่าน AudioManager อย่างอิสระ และเมื่อสูญเสียโฟกัส ให้หยุดการเล่นชั่วคราวผ่านเซสชัน
ตรวจสอบว่าได้ตั้งค่าแฟลก FLAG_HANDLES_MEDIA_BUTTONS และ FLAG_HANDLES_TRANSPORT_CONTROLS แล้ว ตรวจสอบให้แน่ใจว่าเซสชันทำงานอยู่ (setActive(true)) บน Android 12+ ปุ่มสื่อทำงานผ่าน MediaSession เท่านั้น — registerMediaButtonEventReceiver แบบเก่าไม่ได้รับการสนับสนุน
สำหรับการจัดการปุ่มพื้นฐาน — ไม่จำเป็น แต่สำหรับการผสานรวมกับ Android Auto, Wear OS และศูนย์สื่อของระบบ จำเป็นต้องใช้ MediaBrowserService Google แนะนำให้ใช้งาน MediaBrowserService ในแอปทั้งหมดที่มีการเล่นเสียงระยะยาว
ใช้คำสั่ง adb shell dumpsys media_session เพื่อดูเซสชันที่ทำงานอยู่ Callback และ PlaybackState ของมัน ยูทิลิตี้นี้จะแสดงเซสชันที่ลงทะเบียนทั้งหมดพร้อมแท็ก สถานะกิจกรรม และสถานะล่าสุดที่ทราบ — เครื่องมือที่สะดวกสำหรับการดีบัก
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ