Android Studio中如何根据当前显示屏幕控制通知是否展示?
实现方案:Jetpack Compose单Activity架构下控制FCM通知展示
核心思路是跟踪应用前台状态+当前活跃界面/会话标识,在FCM消息接收时根据这两个条件判断是否显示通知。以下是具体实现步骤:
1. 跟踪应用前台状态
首先需要判断应用是否处于前台,后台状态下无论什么界面都要展示通知。
实现应用生命周期观察者
class AppLifecycleObserver : DefaultLifecycleObserver { var isAppInForeground = false private set override fun onResume(owner: LifecycleOwner) { super.onResume(owner) isAppInForeground = true } override fun onPause(owner: LifecycleOwner) { super.onPause(owner) isAppInForeground = false } }
在Application类中注册观察者
class MyApp : Application() { val appLifecycleObserver = AppLifecycleObserver() override fun onCreate() { super.onCreate() ProcessLifecycleOwner.get().lifecycle.addObserver(appLifecycleObserver) } }
2. 跟踪当前活跃的聊天会话/界面
通过DataStore持久化当前打开的聊天会话ID(或界面标识),确保后台服务能获取到最新状态。
定义DataStore存储类
private val Context.dataStore by preferencesDataStore(name = "app_prefs") class AppPrefs(private val context: Context) { private val dataStore = context.dataStore suspend fun setActiveChatId(chatId: String?) { dataStore.edit { preferences -> preferences[ACTIVE_CHAT_ID] = chatId ?: "" } } fun getActiveChatId(): Flow<String?> { return dataStore.data.map { preferences -> val id = preferences[ACTIVE_CHAT_ID] if (id.isNullOrEmpty()) null else id } } companion object { val ACTIVE_CHAT_ID = stringPreferencesKey("active_chat_id") } }
在聊天界面更新会话状态
在聊天界面进入时保存当前会话ID,离开时清空:
@Composable fun ChatScreen(chatId: String, appPrefs: AppPrefs) { // 进入界面时保存当前会话ID LaunchedEffect(chatId) { appPrefs.setActiveChatId(chatId) } // 界面销毁时清空会话ID DisposableEffect(Unit) { onDispose { CoroutineScope(Dispatchers.IO).launch { appPrefs.setActiveChatId(null) } } } // 聊天界面UI逻辑... }
3. 在FCM服务中判断是否展示通知
在FirebaseMessagingService的onMessageReceived方法中,结合前台状态和活跃会话ID判断:
class MyFirebaseMessagingService : FirebaseMessagingService() { private val appPrefs by lazy { AppPrefs(applicationContext) } private val appLifecycleObserver by lazy { (application as MyApp).appLifecycleObserver } override fun onMessageReceived(remoteMessage: RemoteMessage) { super.onMessageReceived(remoteMessage) // 从消息中提取目标会话ID(假设消息data字段包含"chat_id") val messageChatId = remoteMessage.data["chat_id"] val isTargetChatMessage = messageChatId != null // 应用在后台:直接展示通知 if (!appLifecycleObserver.isAppInForeground) { showNotification(remoteMessage) return } // 应用在前台:判断是否处于对应聊天界面 runBlocking { val activeChatId = appPrefs.getActiveChatId().first() // 非聊天消息,或当前打开的会话与消息目标会话不一致时,展示通知 if (!isTargetChatMessage || activeChatId != messageChatId) { showNotification(remoteMessage) } // 否则不展示通知 } } // 你的通知构建逻辑(示例) private fun showNotification(remoteMessage: RemoteMessage) { val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val notificationChannel = NotificationChannel( "chat_channel", "Chat Notifications", NotificationManager.IMPORTANCE_HIGH ) notificationManager.createNotificationChannel(notificationChannel) val notification = NotificationCompat.Builder(this, "chat_channel") .setContentTitle(remoteMessage.notification?.title ?: "新消息") .setContentText(remoteMessage.notification?.body ?: "你有一条新消息") .setSmallIcon(R.drawable.ic_notification) .build() notificationManager.notify(System.currentTimeMillis().toInt(), notification) } }
额外说明
- 如果你的聊天界面没有会话ID(比如通用聊天列表),可以直接跟踪界面路由标识(比如通过NavHost的BackStackEntry获取当前路由),替换会话ID的判断逻辑即可。
- 测试时需覆盖三种场景:应用后台、前台非聊天界面、前台对应聊天界面,确保通知行为符合预期。
内容的提问来源于stack exchange,提问作者Diken Mhrz
相关产品推荐
相关产品推荐

