Designing Notification Systems
📖 Concept
Notification systems on Android are complex due to channels, priority levels, permissions (Android 13+), and battery restrictions. A well-designed notification system drives engagement without annoying users.
Android notification architecture:
Server → FCM → Device → App Process → NotificationManager → System UI
→ WorkManager (data sync)
Notification channels (Android 8.0+):
- Each app must create notification channels for different types
- Users can individually control each channel's importance, sound, vibration
- Cannot modify channel importance after creation (must delete and recreate)
FCM message types:
- Data messages: Handled by your app's FirebaseMessagingService. App controls notification display. Works in foreground and background.
- Notification messages: Displayed automatically by the system when app is in background. Handled by your app only when in foreground.
- Data + Notification: Combined. System shows notification in background; your app handles in foreground.
Best practice: Always use data-only messages — they give you full control over notification display and allow you to sync data before showing the notification.
Notification permission (Android 13+): Must request POST_NOTIFICATIONS runtime permission. Without it, notifications are silently suppressed.
💻 Code Example
1// Complete notification system implementation23// 1. Create notification channels at app startup4class NotificationChannelManager @Inject constructor(5 @ApplicationContext private val context: Context6) {7 fun createChannels() {8 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return910 val channels = listOf(11 NotificationChannel(12 "messages", "Messages",13 NotificationManager.IMPORTANCE_HIGH14 ).apply { description = "New message notifications" },1516 NotificationChannel(17 "updates", "App Updates",18 NotificationManager.IMPORTANCE_DEFAULT19 ).apply { description = "Feature updates and news" },2021 NotificationChannel(22 "sync", "Background Sync",23 NotificationManager.IMPORTANCE_LOW24 ).apply {25 description = "Data synchronization"26 setShowBadge(false)27 }28 )2930 val manager = context.getSystemService(NotificationManager::class.java)31 manager.createNotificationChannels(channels)32 }33}3435// 2. FCM Service — handle data messages36class MyFirebaseService : FirebaseMessagingService() {37 override fun onMessageReceived(message: RemoteMessage) {38 val data = message.data39 when (data["type"]) {40 "new_message" -> handleNewMessage(data)41 "sync_trigger" -> scheduleSyncWork()42 "silent_update" -> handleSilentUpdate(data)43 }44 }4546 private fun handleNewMessage(data: Map<String, String>) {47 val notification = NotificationCompat.Builder(this, "messages")48 .setSmallIcon(R.drawable.ic_message)49 .setContentTitle(data["sender_name"])50 .setContentText(data["preview"])51 .setAutoCancel(true)52 .setContentIntent(createPendingIntent(data["conversation_id"]))53 .setStyle(NotificationCompat.MessagingStyle(selfPerson)54 .addMessage(data["preview"], System.currentTimeMillis(), senderPerson))55 .addAction(R.drawable.ic_reply, "Reply", createReplyPendingIntent())56 .build()5758 NotificationManagerCompat.from(this).notify(59 data["conversation_id"].hashCode(),60 notification61 )62 }6364 override fun onNewToken(token: String) {65 // Send new token to your server66 CoroutineScope(Dispatchers.IO).launch {67 api.updateFcmToken(token)68 }69 }70}7172// 3. Request notification permission (Android 13+)73@Composable74fun NotificationPermissionRequest() {75 val permissionState = rememberPermissionState(76 Manifest.permission.POST_NOTIFICATIONS77 )7879 LaunchedEffect(Unit) {80 if (!permissionState.status.isGranted) {81 permissionState.launchPermissionRequest()82 }83 }84}
🏋️ Practice Exercise
Practice:
- Implement notification channels for 3 different notification types
- Handle FCM data messages and display rich notifications with actions
- Implement notification grouping for multiple messages from the same sender
- Set up FCM token refresh and server registration
- Handle the Android 13 POST_NOTIFICATIONS permission gracefully
⚠️ Common Mistakes
Using notification messages instead of data messages — you lose control over notification content and behavior in background
Not creating notification channels on Android 8.0+ — notifications silently fail
Sending FCM token only once — tokens can refresh, always handle onNewToken
Not requesting POST_NOTIFICATIONS permission on Android 13+ — notifications are suppressed
💼 Interview Questions
🎤 Mock Interview
Mock interview is powered by AI for Designing Notification Systems. Login to unlock this feature.