如何让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
相关产品推荐
相关产品推荐

