โ† THE WRITING

How to display notifications in 2020

These days, most startup apps heavily rely on third-party libraries to send push notifications to a user, thus causing developers to usually not pay too much attention to Android notification changes.

For example, I was working on my side-project which sends a notification once the download is completed (was checking how DownloadManager works).

Back in 2016, you’d need to initialize NotificationManager and pending intent if notification contains custom action:

private lateinit var notificationManager: NotificationManager
private lateinit var pendingIntent: PendingIntent

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

    val intent = Intent(this, DetailActivity::class.java)
    pendingIntent =
        PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}

And then after download is complete, you’d need to build the notification, include pendingIntent and send it to notification manager:

val builder = NotificationCompat.Builder(context)
    .setSmallIcon(R.drawable.ic_assistant_black_24dp)
    .setContentTitle(getString(R.string.notification_title))
    .setContentText(getString(R.string.notification_description))
    .setPriority(NotificationCompat.PRIORITY_MAX)
    .addAction(R.drawable.icon, getString(R.string.notification_button), pendingIntent)

notificationManager.notify(1, builder.build())

After writing code and running the app, the notification wasn’t getting displayed. I thought maybe I was incorrectly implementing DownloadManager since I had just started playing around with it. So, after some debugging, I saw that the DownloadManager worked flawlessly and notificationBuilder did in-fact get called, but nothing was displayed ๐Ÿคฆโ€. The next obvious step was to google the issue. The first stackOverflow answer mentioned the following change in NotificationManager for Android O and above.

๐Ÿ’กSo for the devices running on Android O and above, it’s required to create a channel for different kind of notifications where id, name and importance should be passed in constructor:

override fun onCreate(savedInstanceState: Bundle?) {
    ...

    notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel = NotificationChannel(
            CHANNEL_ID,
            getString(R.string.notification_title),
            NotificationManager.IMPORTANCE_HIGH
        )
        notificationManager.createNotificationChannel(channel)
    }
}
The same channel id should be passed in notificationBuilder’s constructor alongside with context:
val builder = NotificationCompat.Builder(context, CHANNEL_ID)

Made the changes, the notification got displayed! But the action button didn’t work ๐Ÿ˜’. After another round of googling, I found out the addAction method in notificationBuilder now requires an Action class, which is basically a wrapper of the arguments addAction method used to accept.

The full code of sending and displaying notifications nowadays is below:

private lateinit var notificationManager: NotificationManager
private lateinit var action: NotificationCompat.Action

override fun onCreate(savedInstanceState: Bundle?) {
    ...

    notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel = NotificationChannel(
            CHANNEL_ID,
            getString(R.string.notification_title),
            NotificationManager.IMPORTANCE_HIGH
        )
        notificationManager.createNotificationChannel(channel)
    }

    val intent = Intent(this, DetailActivity::class.java)
    val pendingIntent =
        PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT)
    action = NotificationCompat.Action.Builder(
        R.drawable.icon, getString(R.string.notification_button), pendingIntent
    ).build()
}
...

private fun downloadCompleted() {
  val builder = NotificationCompat.Builder(context, CHANNEL_ID)
      .setSmallIcon(R.drawable.ic_assistant_black_24dp)
      .setContentTitle(getString(R.string.notification_title))
      .setContentText(getString(R.string.notification_description))
      .setPriority(NotificationCompat.PRIORITY_MAX)
      .addAction(action)

  notificationManager.notify(1, builder.build())
}

Hopefully, this article was helpful and stay tuned for another then-and-now article!

THANKS FOR READING

More notes, as I figure things out.

Get the next letter by email, follow via RSS, or say hello on X.