You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

开发媒体播放器:应用被杀死时如何保持通知持久显示?

解决媒体播放器应用杀死后通知消失的问题

我来帮你一步步分析和解决这个问题:

核心问题分析

你遇到的情况是:应用被杀死后通知消失,但音乐仍在播放,这说明你的Service还在后台运行,但前台状态被系统移除了,导致通知消失;而未杀死应用时通知正常,说明正常播放流程里的前台服务设置是没问题的。另外锁屏通知没有控制按钮,也和通知的配置、MediaSession的设置有关。

具体解决方案

1. 必须创建NotificationChannel(Android O+ 强制要求)

从Android 8.0(API 26)开始,所有通知都必须关联到一个NotificationChannel,否则通知可能无法正常显示,或者在应用被杀死后被系统自动清理。你需要在创建通知前添加channel的创建代码:

private fun createNotificationChannel() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channelId = "media_player_channel"
        val channelName = "Media Player Controls"
        val channelDescription = "Notification channel for media playback controls"
        val importance = NotificationManager.IMPORTANCE_HIGH // 高优先级确保通知显示在锁屏且有声音提示
        val channel = NotificationChannel(channelId, channelName, importance).apply {
            description = channelDescription
            setShowBadge(false)
            lockscreenVisibility = Notification.VISIBILITY_PUBLIC // 确保锁屏可见
        }
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(channel)
    }
}

然后在buildNotification方法开头调用这个函数,并且在Notification.Builder里指定channelId:

var builder: Notification.Builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    Notification.Builder(this, "media_player_channel")
} else {
    Notification.Builder(this)
}
// 接着设置其他属性...

2. 确保Service在播放期间始终保持前台状态

当音乐正在播放时,你的Service必须一直处于前台状态,不能随意退出前台。目前你在pauseMedia里调用了stopForeground(false),这会让Service退出前台但保留通知,这没问题;但要确保在恢复播放时,重新调用startForeground,把Service变回前台状态。

另外,当用户杀死应用时,系统可能会触发onTaskRemoved方法,你可以在这里重新激活前台服务,避免通知消失:

override fun onTaskRemoved(rootIntent: Intent?) {
    super.onTaskRemoved(rootIntent)
    // 如果音乐还在播放,重新启动前台服务
    if (mp?.isPlaying == true) {
        // 重新构建通知并调用startForeground
        val playPauseAction = if (mp!!.isPlaying) {
            generateAction(Icon.createWithResource(baseContext, R.drawable.pause), "Pause", ACTION_PAUSE)
        } else {
            generateAction(Icon.createWithResource(baseContext, R.drawable.play), "Play", ACTION_PLAY)
        }
        buildNotification(playPauseAction)
    }
}

3. 正确关联MediaSession并设置回调

你的MediaStyle已经关联了MediaSession,但需要确保MediaSession被正确激活,并且设置了回调来处理播放状态变化,这样系统才能正确识别播放状态,维护通知的存在:

private lateinit var mediaSession: MediaSessionCompat

override fun onCreate() {
    super.onCreate()
    // 初始化MediaSession
    mediaSession = MediaSessionCompat(this, "MediaPlayerSession")
    mediaSession.isActive = true // 激活MediaSession
    // 设置回调处理播放控制
    mediaSession.setCallback(object : MediaSessionCompat.Callback() {
        override fun onPlay() {
            // 恢复播放逻辑
            resumeMedia()
        }

        override fun onPause() {
            // 暂停播放逻辑
            pauseMedia()
        }

        override fun onRewind() {
            // 快退逻辑
            mp?.seekTo(mp!!.currentPosition - 10000)
        }

        override fun onFastForward() {
            // 快进逻辑
            mp?.seekTo(mp!!.currentPosition + 30000)
        }
    })
}

override fun onDestroy() {
    super.onDestroy()
    mediaSession.isActive = false // 销毁时关闭MediaSession
    mediaSession.release()
    // 释放MediaPlayer,避免音乐继续播放
    mp?.stop()
    mp?.release()
    mp = null
    stopForeground(true)
}

4. 修复锁屏通知没有控制按钮的问题

锁屏通知没有控制按钮,主要是因为MediaSession没有正确设置播放状态,以及通知的MediaStyle没有正确配置。确保在播放状态变化时,更新MediaSession的播放状态:

比如在播放开始时:

private fun startMedia() {
    mp?.start()
    // 更新MediaSession状态
    mediaSession.setPlaybackState(PlaybackStateCompat.Builder()
        .setState(PlaybackStateCompat.STATE_PLAYING, mp!!.currentPosition, 1.0f)
        .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE or PlaybackStateCompat.ACTION_REWIND or PlaybackStateCompat.ACTION_FAST_FORWARD)
        .build())
    // 调用buildNotification更新通知
    buildNotification(generateAction(Icon.createWithResource(baseContext, R.drawable.pause), "Pause", ACTION_PAUSE))
}

暂停时:

private fun pauseMedia() {
    if (mp!!.isPlaying) {
        mp!!.pause()
        resumePosition = mp!!.currentPosition
        // 更新MediaSession状态
        mediaSession.setPlaybackState(PlaybackStateCompat.Builder()
            .setState(PlaybackStateCompat.STATE_PAUSED, mp!!.currentPosition, 1.0f)
            .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE or PlaybackStateCompat.ACTION_REWIND or PlaybackStateCompat.ACTION_FAST_FORWARD)
            .build())
        stopForeground(false)
    }
}

这样系统就能识别播放状态,在锁屏上显示对应的控制按钮了。

额外注意点

  • 确保你的MediaPlayerService是用startForegroundService启动的(Android O+ 要求),而不是普通的startService。
  • 在onDestroy里一定要释放MediaPlayer,避免音乐在Service销毁后继续播放的异常情况。

内容的提问来源于stack exchange,提问作者kn0wmad1c

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:30:19