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

如何实现仅在通知可见时更新通知文本?

Android 按需更新持久化通知:检测通知可见性

方法1:官方推荐 - 使用NotificationListenerService

这是系统提供的专门监听通知状态的服务,能精准捕获通知的可见性变化:

  • 核心回调onNotificationVisibilityChanged()(Android 11及以上可用):当通知的显示状态切换时触发,参数里的visibility会明确告诉你当前通知是处于锁屏公开显示、状态栏展开可见还是完全隐藏状态
  • 实现步骤:
    1. 自定义服务继承NotificationListenerService,重写上述回调
    2. 在Manifest中注册服务,并声明权限
    3. 引导用户在系统设置中开启「通知访问」权限

示例代码(Kotlin):

class MyNotificationListener : NotificationListenerService() {
    override fun onNotificationVisibilityChanged(sbn: StatusBarNotification, visibility: Int) {
        super.onNotificationVisibilityChanged(sbn, visibility)
        // 先判断是不是我们自己的通知
        if (sbn.packageName == packageName && sbn.tag == "MY_PERSISTENT_NOTIFICATION") {
            when (visibility) {
                // 通知在锁屏(公开模式)或状态栏下拉可见,触发更新
                VISIBILITY_PUBLIC -> updateNotificationContent()
                // 通知在锁屏私密模式,只有我们的通知是非私密时才更新
                VISIBILITY_PRIVATE -> {
                    if (!sbn.notification.flags.contains(Notification.FLAG_PRIVATE)) {
                        updateNotificationContent()
                    }
                }
                // 通知完全隐藏,停止更新
                VISIBILITY_SECRET -> stopNotificationUpdate()
            }
        }
    }

    // 更新通知内容的逻辑
    private fun updateNotificationContent() {
        val updatedNotification = NotificationCompat.Builder(this, "MY_CHANNEL_ID")
            .setSmallIcon(R.drawable.ic_notify)
            .setContentTitle("实时更新")
            .setContentText("当前时间:${System.currentTimeMillis()}")
            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) // 设为公开模式,支持锁屏显示
            .build()
        NotificationManagerCompat.from(this).notify("MY_PERSISTENT_NOTIFICATION", 1, updatedNotification)
    }

    // 停止更新的逻辑(比如取消定时器)
    private fun stopNotificationUpdate() {
        // 这里可以取消之前的定时任务
    }
}

方法2:兼容低版本 - 使用AccessibilityService

如果要支持Android 10及以下,辅助服务可以监听系统窗口变化,间接判断通知是否可见:

  • 监听TYPE_WINDOW_STATE_CHANGED事件,识别状态栏下拉面板(窗口类名含NotificationPanel)或锁屏窗口(类名含Keyguard)的显示状态
  • 当这些窗口显示时,触发通知更新;窗口隐藏则停止

示例代码片段:

class MyAccessibilityService : AccessibilityService() {
    override fun onAccessibilityEvent(event: AccessibilityEvent) {
        if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
            val windowClass = event.source?.windowInfo?.className ?: return
            // 判断是否是通知面板或锁屏
            val isNotifyPanelVisible = windowClass.contains("NotificationPanel")
            val isLockScreenVisible = windowClass.contains("Keyguard")
            
            // 锁屏时要确保自己的通知是非私密的才更新
            if (isNotifyPanelVisible || (isLockScreenVisible && isMyNotificationPublic())) {
                updateNotificationContent()
            } else {
                stopNotificationUpdate()
            }
        }
    }

    // 判断自己的通知是否为公开模式
    private fun isMyNotificationPublic(): Boolean {
        val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
        val myNotification = notificationManager.activeNotifications.find { 
            it.tag == "MY_PERSISTENT_NOTIFICATION" 
        }
        return myNotification?.notification?.flags?.contains(Notification.FLAG_PRIVATE) == false
    }

    // 省略updateNotificationContent和stopNotificationUpdate方法
}

注意:辅助服务需要用户手动在系统设置中开启,权限较高,优先用第一种方法。

优化技巧

  • 用定时器(比如Coroutine的flow.timer或Handler)实现周期性更新,但只有在通知可见时才启动定时器,不可见立即取消,避免无效消耗
  • 创建通知时务必设置setVisibility(NotificationCompat.VISIBILITY_PUBLIC),确保锁屏时能正常显示并触发更新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 23:01:37