Computer scienceMobileAndroidUser InterfaceUI components

Posting notifications

16 minutes read

Notifications are a common way of interacting with a user outside of an app, and you probably encounter lots of them during an average day. They provide short, time-related information about events from your app. In this topic, you will learn how to create and modify notifications.

Starting from Android 13, we need to request a runtime permission before showing notifications.

Creating a notification channel

Before building a notification, you need to create a channel. Notification channels allow users to gain control over notifications. They make it easier to divide different notification types and let you customize the system behavior for specified alerts. Users can change whether they want a particular kind of notification to emit sound, make the device vibrate, or be visible at all. Since Android 8, all notifications must be assigned to a channel. Otherwise, the system will log an error, and the notification won't appear.

Creating a notification channel is easy:

  1. Come up with a unique channel ID.

  2. Choose a name for your channel.

  3. Create a description (this step is optional as the channel name may be self-explanatory).

  4. Select the importance level: Urgent, High, Medium, or Low.

  5. Pass these elements to createNotificationChannel() (note that it's not possible to make any changes to the notification's behavior after this step).

That's it. The channel is ready to go.

The meanings of the importance levels are shown below:

  • Urgent: Makes a sound and pops up on the screen. Useful for things like messages, reminders, and so on. Be careful with this one — they can be annoying!

  • High: Makes a sound and stays in the notifications panel.

  • Medium: Doesn't make a sound but does stay in the notifications panel.

  • Low: Doesn't make a sound, doesn't appear in the status bar and goes to the bottom of the notifications panel.

It's now time to look at a code example that's based around a food delivery app.

To avoid issues such as a courier having to wait 15 minutes for someone to pick up their food, you want your app to notify the user about their delivery status. This is important, so we'll use the High importance level.

Let's follow the instruction from the numbered list above:

// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is not in the support library
const val CHANNEL_ID = "deliveryStatus"

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val name = "Delivery status"
    val descriptionText = "Your delivery status"
    val importance = NotificationManager.IMPORTANCE_HIGH
    val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
        description = descriptionText
    }
    // Register the channel with the system
    val notificationManager: NotificationManager =
        getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    notificationManager.createNotificationChannel(channel)
}

Building a notification

With the notification channel created, we can move on to building the notification itself. A basic notification consists of an icon, a title, and some text. To create a notification, you need to set its content (icon, title, text, etc.) and a channel using the NotificationCompat.Builder object. NotificationCompat.Builder requires a context and the channel ID you created earlier to be passed to its parameters, as you can see in the below example:

val notificationBuilder = NotificationCompat.Builder(context, CHANNEL_ID)
    .setSmallIcon(R.drawable.photo)
    .setContentTitle("Delivery")
    .setContentText("Food is ready!")
    .setPriority(NotificationCompat.PRIORITY_HIGH)

So, why does this example include .setPriority()? Haven't we already defined that in the notification channel? Well, yes, but this additional line is for compatibility with older versions of Android. If the app is running on version 8 or higher, it will be ignored.

Another potential problem is that your notification text (.setContentText()) might not be shown correctly if it's too long. You won't currently be able to expand the notification to read the whole thing, but you can easily fix this by adding .setStyle(NotificationCompat.BigTextStyle()):

.setContentText("Food is ready!")
.setStyle(NotificationCompat.BigTextStyle())

With this applied, the notification will be expandable, and you will have much more space for your content. By adding the .bigText() after the .BigTextStyle() you can change the contents of the notification when expanded. Pass the text which you would like to show in the expanded notification in the .bigText() and it will work:

.setContentText("Food is ready!")
.setStyle(NotificationCompat.BigTextStyle().bigText("Some long text message"))

You might also want to trigger an action when the user clicks your notification, such as redirecting them to your app. You can do this with the help of a PendingIntent. After creating the PendingIntent with the required action, simply add it to your notification:

.setContentIntent(pendingIntent)

You can (and probably should) automatically cancel the notification after the user clicks on it. You may also want your notification to expire after some time. Here's how:

.setAutoCancel(true) // automatically remove notification after click
.setTimeoutAfter(1000) // remove notification after some time in milliseconds

If the notification is likely to be updated in the future, but you don't want to disturb the user with more notification sounds, you can also add:

.setOnlyAlertOnce(true)

The final code looks like this:

val notificationBuilder = NotificationCompat.Builder(context, CHANNEL_ID)
    .setSmallIcon(R.drawable.photo)
    .setContentTitle("Delivery")
    .setContentText("Food is ready!")
    .setStyle(NotificationCompat.BigTextStyle())
    .setPriority(NotificationCompat.PRIORITY_HIGH)
    .setAutoCancel(true)
    .setContentIntent(pi)

Show the notification

We're almost there! To make your notification appear, you need to get a NOTIFICATION_SERVICE as a NotificationManager and call the notify() method. You should pass a unique notification ID and NotificationCompat.Builder.build() as arguments to this method. Make sure you keep a record of the notification ID! You will need it later to update or remove the notification.

val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(1, notificationBuilder.build())

After this call, your notification should appear in the notification panel.

Update or remove a notification

To update an existing notification, follow the steps described in the "Show the notification" section, but this time supply the same ID used to create the original notification. This will ensure that your notification is replaced with the new one. (Android will create a new notification if the previous one has already been dismissed.)

To remove a notification, call the cancel() method with the notification ID. You can also use cancelAll() to remove everything:

notificationManager.cancel(1)
// or 
notificationManager.cancelAll()

Conclusion

In this topic, you learned how to create and customize notifications. You also found out how to update and remove existing notifications and discovered why notification channels are so important. It's now time for some practice!

33 learners liked this piece of theory. 0 didn't like it. What about you?
Report a typo