Android:如何基于MediaSession确定当前正在播放的音乐应用?
解决Android多MediaSession下判断当前播放应用的问题
你遇到的核心问题是会话切换时状态更新存在延迟,只靠OnActiveSessionsChangedListener的单次回调没法及时拿到最新的播放状态。正确的做法是结合「会话变化监听」+「每个会话的播放状态实时监听」,双管齐下:
1. 给每个MediaController注册PlaybackState回调
不要只在会话变化时一次性检查状态,而是给每个活跃的MediaController注册PlaybackStateCallback,这样无论何时播放状态变化(包括切换应用时的状态更新),你都能第一时间收到通知:
private val playbackStateCallback = object : MediaController.Callback() { override fun onPlaybackStateChanged(state: PlaybackState?) { super.onPlaybackStateChanged(state) // 当状态变为播放时,更新当前控制器 if (state?.state == PlaybackState.STATE_PLAYING) { currentMediaController = this@YourClass.mMediaController } // 可选:如果状态变为暂停/停止,且当前控制器是它,重新检查活跃会话 else if (state?.state in listOf(PlaybackState.STATE_PAUSED, PlaybackState.STATE_STOPPED) && currentMediaController == this@YourClass.mMediaController) { checkActivePlayingSession() } } override fun onMetadataChanged(metadata: MediaMetadata?) { super.onMetadataChanged(metadata) // 如果当前控制器是这个,同步更新歌曲信息 if (currentMediaController == this@YourClass.mMediaController) { updateSongInfo(metadata) } } }
2. 在会话变化时管理回调注册
在OnActiveSessionsChangedListener中,不仅要遍历检查当前状态,还要给新的会话注册回调,同时给移除的会话取消注册,避免内存泄漏:
// 维护旧会话列表,用于取消回调注册 private val oldControllers = mutableListOf<MediaController>() private val mSessionsChangedListener = MediaSessionManager.OnActiveSessionsChangedListener { list -> list?.let { controllers -> // 取消旧会话的回调注册 oldControllers.forEach { controller -> controller.unregisterCallback(playbackStateCallback) } // 更新旧会话列表 oldControllers.clear() oldControllers.addAll(controllers) // 给新会话注册回调 controllers.forEach { controller -> controller.registerCallback(playbackStateCallback) } // 初始检查当前正在播放的会话 checkActivePlayingSession() } } // 辅助方法:遍历活跃会话找正在播放的 private fun checkActivePlayingSession() { currentMediaController = oldControllers.firstOrNull { it.playbackState?.state == PlaybackState.STATE_PLAYING } // 如果找到,直接更新歌曲信息 currentMediaController?.let { updateSongInfo(it.metadata) } }
3. 额外注意事项
- 权限方面:Android 12及以下需申请
android.permission.MEDIA_CONTENT_CONTROL,Android 13+需申请android.permission.READ_MEDIA_PLAYBACK_STATE,否则无法获取会话信息。 - 部分媒体应用切换时会先暂停旧会话、再启动新会话,这时
onPlaybackStateChanged会触发两次,你的回调能准确捕捉到状态变化。
内容的提问来源于stack exchange,提问作者Ziad Halabi
相关产品推荐
相关产品推荐

