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

如何让Android前台服务通知仅在应用关闭或后台时显示?

实现Android前台服务通知仅在应用后台/关闭时显示

要实现这个需求,核心是跟踪应用的前后台状态,并根据状态动态控制前台服务的通知显示。以下是具体修改步骤和代码:

1. 跟踪应用前后台状态(修改Application类)

在NotificationApplication中注册Activity生命周期回调,维护应用是否在前台的状态:

class NotificationApplication : Application(), Application.ActivityLifecycleCallbacks {

    var isAppInForeground = false
        private set

    override fun onCreate() {
        super.onCreate()
        registerActivityLifecycleCallbacks(this)
        
        // 原有通知渠道创建代码
        val channel = NotificationChannel(
            "notification_channel_id",
            "Notifications",
            NotificationManager.IMPORTANCE_HIGH
        )
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(channel)
    }

    override fun onActivityResumed(activity: Activity) {
        isAppInForeground = true
    }

    override fun onActivityPaused(activity: Activity) {
        // 延迟1秒判断,避免Activity切换时的误判
        Handler(Looper.getMainLooper()).postDelayed({
            isAppInForeground = checkIfAppInForeground()
        }, 1000)
    }

    // 辅助方法:判断应用是否处于前台
    private fun checkIfAppInForeground(): Boolean {
        val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        val runningProcesses = activityManager.runningAppProcesses ?: return false
        
        for (process in runningProcesses) {
            if (process.processName == packageName && process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                return true
            }
        }
        return false
    }

    // 以下为未用到的生命周期方法,空实现即可
    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
    override fun onActivityStarted(activity: Activity) {}
    override fun onActivityStopped(activity: Activity) {}
    override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
    override fun onActivityDestroyed(activity: Activity) {}
}

2. 修改按钮点击逻辑(MainActivity)

点击按钮时先判断应用是否在后台,仅在后台时启动服务:

class MainActivity : ComponentActivity() {
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 动态申请POST_NOTIFICATIONS权限(Android 13+需要)
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), 101)
        }

        enableEdgeToEdge()
        setContent {
            Box(
                contentAlignment = Alignment.Center,
                modifier = Modifier.fillMaxSize()) {
                Button(onClick = {
                    val app = application as NotificationApplication
                    if (!app.isAppInForeground) {
                        // 应用在后台,启动服务
                        Intent(applicationContext, NotificationService::class.java).also {
                            it.action = "Start"
                            startService(it)
                        }
                    } else {
                        // 应用在前台,提示用户
                        Toast.makeText(this@MainActivity, "应用当前在前台,不显示通知", Toast.LENGTH_SHORT).show()
                    }
                }) {
                    Text(text = "后台时显示通知")
                }
            }
        }
    }
}

3. 动态控制前台通知(修改NotificationService)

服务中监听应用前后台变化,自动切换通知显示状态:

class NotificationService : Service(), Application.ActivityLifecycleCallbacks {

    private lateinit var app: NotificationApplication
    private val NOTIFICATION_ID = 1

    override fun onCreate() {
        super.onCreate()
        app = application as NotificationApplication
        app.registerActivityLifecycleCallbacks(this)
    }

    override fun onBind(intent: Intent?): IBinder? {
        return null
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        when(intent?.action) {
            "Start" -> updateForegroundNotificationStatus()
        }
        return START_STICKY // 服务被系统杀死后自动重启
    }

    // 根据应用状态更新前台通知
    private fun updateForegroundNotificationStatus() {
        if (!app.isAppInForeground) {
            // 应用在后台,显示前台通知
            val notification = NotificationCompat.Builder(this, "notification_channel_id")
                .setSmallIcon(R.drawable.ic_launcher_foreground)
                .setContentTitle("后台服务")
                .setContentText("服务正在后台运行")
                .build()
            startForeground(NOTIFICATION_ID, notification)
        } else {
            // 应用在前台,移除通知但保持服务运行
            stopForeground(STOP_FOREGROUND_REMOVE)
        }
    }

    override fun onActivityResumed(activity: Activity) {
        // 应用回到前台,更新通知状态
        updateForegroundNotificationStatus()
    }

    override fun onActivityPaused(activity: Activity) {
        // 应用进入后台,延迟判断后更新状态
        Handler(Looper.getMainLooper()).postDelayed({
            updateForegroundNotificationStatus()
        }, 1000)
    }

    // 未用到的生命周期方法空实现
    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
    override fun onActivityStarted(activity: Activity) {}
    override fun onActivityStopped(activity: Activity) {}
    override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
    override fun onActivityDestroyed(activity: Activity) {}

    override fun onDestroy() {
        super.onDestroy()
        // 解绑生命周期监听
        app.unregisterActivityLifecycleCallbacks(this)
    }
}

4. 完善AndroidManifest配置

确保服务的前台服务类型配置正确(以specialUse为例,需说明用途):

<service
    android:name=".NotificationService"
    android:foregroundServiceType="specialUse">
    <!-- 说明前台服务的用途,需符合Google的政策要求 -->
    <property
        android:name="android.app.PROPERTY_SPECIAL_USE_FOREGROUND_SERVICE"
        android:value="后台任务状态提醒"/>
</service>

关键说明

  • 状态判断延迟:在onActivityPaused中延迟1秒判断,是为了避免用户在应用内切换Activity时被误判为进入后台。
  • 服务存活:使用START_STICKY让服务在被系统回收后自动重启,保证后台任务的连续性。
  • 权限申请:Android 13及以上必须动态申请POST_NOTIFICATIONS权限,否则通知无法显示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 01:31:05