Photo by Noelle Otto from Pexels

Android Notifications in 5 Minutes

Notifications are one of the fastest and easiest ways to add more interactivity and engagement to your apps. Notifications provide quick snippets of information that your users need to know right now. Notifications also allow users to quickly take actions on events. We’ll work through all the most used examples of notifications and you’ll be notifying your users in no time.

Building a Notification

The first step to showing a notification to the user is to build the notification object. The Notification is built up using a NotificationCompat.Builder . The minimum information that is needed to display a Notification is: a small icon. That’s it, but its not very useful. Notifications should be useful to the user, so that will usually involve a title and a body. Below is a diagram of a common notification with the important bits labeled.

  • Small icon will be shown in the status bar, and it is important to know that they will be painted over in color. The reason this is important is is you’ll need an icon with alpha. If there is no alpha in the icon, you’ll end up with a great white square instead of your own branding.
  • Content title is the well, title of your content. This should be a short description of why the notification is being shown.
  • Content body is a bit of detail on your notification. You should be cognizant of how much text you are putting in the body, with the normal configuration you will be limited to one line of text.
  • Large icon is a Bitmap related to your notification. This can be something like a profile image.

The code is fairly simple to put this together as shown below.

val notification = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_announcement)
.setContentTitle(title)
.setContentText(body)
.build()

Showing a Notification

Now that the notification is built we have to find a way to show it. Android provides a system service show notifications to the user. NotificationManagerCompat will allow the application to notify the user. To notify the user, we must provide a notificationId and the built notification.

with(NotificationManagerCompat.from(context)) {
if (getNotificationChannel(CHANNEL_ID) == null) {
createNotificationChannel(context)
}
notify(notificationId, builder.build())
}

There is an extra bit of code in there, the check for if the notification channel exists.

Channels and Importance

Channels were introduced in Oreo, and allow users to select which notifications their applications can show them. As application developers we should silo our notifications based on their topic. If an application uses only one channel for all of its notifications, the user would not be able to select which notifications they want to see and if they blocked one channel, they would no longer get notifications from the application.

fun createNotificationChannel(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = context.getString(R.string.channel_name)
val descriptionText = context.getString(R.string.channel_description)
val importance = NotificationManager.IMPORTANCE_HIGH
val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
description = descriptionText
}
NotificationManagerCompat.from(context).createNotificationChannel(channel)
}
}

A channel should have the following information

  • ID, an identifier for our channel, this should be a String constant in your application.
  • Name, this should communicate to the user what sort of notifications are in the channel something short and simple like “Messages” work for this.
  • Importance, this can be High, Default, Low, or Min, how high you set this results in how much user interference there will be when you notify the user
  • Description, this will show in the Android settings menu and should describe in greater detail about the channel

Responding to User Actions

There are multiple ways a user can interact with a notification. Luckily the API to handle how they interact with notifications are all fairly similar. Intents and PendingIntents are used to communicate back to the application and allow some sort of handling logic to take place.

The simplest way to handle a large amount of notifications is through the use of a BroadcastReceiver. When a user performs an action on a notification, the Intent will be fired and the BroadcastReceiver’s onReceive method will be invoked.

val builder = NotificationCompat.Builder(context, CHANNEL_ID)
...
.setContentIntent(onContentTapped /** Pending intent */)
.setDeleteIntent(onSwipedAway /** Pending intent */)
.addAction(
R.drawable.ic_announcement,
actionTitle,
onActionTapped /** Pending intent */
)
  • ContentIntent will be fired when the user taps on the notification. It is important to note the notification will not be dismissed unless you also call setAutoCancel(true) on the notification.
  • DeleteIntent will be fired when the user swipes away the notification.
  • Actions are the buttons at the bottom of the notification. These also have icons, and titles required.

To create your BroadcastReceiver you’ll need to extend the BroadcastReceiver class, override the onReceive method, and do not forget to declare the Receiver in the AndroidManifest.xml.

class NotificationBroadcastReceiver : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {
val action = intent.action

when (action) {
ACTION_ONE -> {
Toast.makeText(context, "Action One hit!", Toast.LENGTH_SHORT).show()
}
ACTION_TWO -> {
Toast.makeText(context, "Action Two hit!", Toast.LENGTH_SHORT).show()
}
}
}

}
object NotificationController {
fun pendingIntent(context: Context, name: String, extras: Bundle?): PendingIntent {
val intent = Intent(context, NotificationBroadcastReceiver::class.java).apply {
action = name
putExtra(EXTRA_NOTIFICATION_ID, extras)
}

return PendingIntent.getBroadcast(context, 0, intent, 0)
}
}

NotificationController is a quick utility to create PendingIntents for notifications. The most important thing is to create differently named actions to correctly handle how the user interacted with the notification. Also if you are going to launch an Activity from the BroadcastReceiver you must use the IntentFlag NEW_TASK. It’s a small price to pay to handle all notifications in a common place in my mind. Intents can also be registered to different BroadcastReceivers, so you could limit the scope to one BroadcastReceiver per type of notification.

If you have any questions about notifications check out the docs or ask in the comments below. There are plenty of great examples in the documentation, but hopefully I gave you enough to get started.

Thanks for reading!