Notifications are one of the most important tools for interaction between the application and the user in the ecosystem Android. They allow you to inform about new messages, remind you about scheduled events, or display the status of background tasks even when the application is not active on the screen. Proper implementation of this mechanism directly affects audience retention and ease of use of your software product. However, starting from version Android 8.0 (Oreo), the approach to working with notifications has changed dramatically, introducing the mandatory use of channels.

In this article we will analyze in detail the process of creating, configuring and displaying notifications, taking into account all modern platform requirements. You will learn how to properly initialize NotificationManager, customize the visual design and avoid common mistakes due to which notifications may simply not appear on the userโ€™s device. Understanding these nuances is critical for any developer seeking to create a quality application.

Notification system architecture and channels

Notification channels have become the fundamental unit of organizing alerts in modern versions of the operating system. A channel is a category that groups notifications of the same type, such as Chats, News, or System Messages. The user can independently manage each channel: turn off sound, vibration, or completely block display for a specific group, without affecting the operation of the entire application. This gives the user fine control over what exactly is important for him to see.

The programmer is required to create a channel before sending the first notification. If you try to post a message to a non-existent channel, the system will simply ignore your request and the user will not see anything. The channel ID must be unique within your application and remain unchanged after the first publication. It is impossible to change the channel settings (for example, importance or sound) programmatically after its creation - this can only be done by the user in the device settings.

To create a channel, a class is used NotificationChannel, to which the ID, display name and importance level are passed. The severity level (importance) determines the behavior of the notification: whether it will appear as a pop-up window, make a sound, or simply appear quietly in the curtain. Below are the main levels that can be used during initialization:

  • ๐Ÿ”ฅ IMPORTANCE_HIGH: the notification appears on top of other applications and makes a sound (used for calls and urgent messages).
  • ๐Ÿ”” IMPORTANCE_DEFAULT: the notification makes a sound, but does not block the screen (standard behavior for instant messengers).
  • ๐Ÿคซ IMPORTANCE_LOW: the notification does not make a sound and does not pop up, being displayed only in the panel notifications.
  • ๐Ÿšซ IMPORTANCE_NONE: notifications for this channel will not be displayed to the user at all.

โš ๏ธ Attention: After a channel has been created and at least one notification has been sent through it, any attempts to change its settings (sounds, vibration, importance) through the code will be ignored by the system. To reset the channel settings for testing, you will have to remove the application from the device or clear its data through the system settings.

๐Ÿ’ก

Use clear names for notification channels, since these are the names the user will see in the system settings of their smartphone. Avoid technical identifiers like "channel_01".

Initializing the NotificationManager and constructing the object

To manage notifications in Android, a system service is used NotificationManager. You can access it through the app or activity context by calling the method getSystemService. This is the central dispatcher that accepts your requests to publish, update, or cancel alerts. Without a correct reference to this manager, no action with notifications will be performed.

The notification content is directly created using the Builder design pattern, implemented by the class NotificationCompat.Builder. Using the compatible version (Compat) is highly recommended as it guarantees correct operation on older versions of Android, providing a unified programming interface. The context and ID of the channel that you created at the previous stage are necessarily transferred to the builder constructor.

In the process of building an object, you set the main visual and behavioral parameters. This includes the small icon (small icon) that appears in the status bar, title, and text content. Also here you configure the action that will happen when you click on a notification, usually this is the opening of a specific application activity. All these parameters are packed into the final class object. data-i="59">. It tells the system that the notification should be automatically removed from the panel after the user clicks on it. If you do not set this flag, the notification will remain hanging in the curtain until the user brushes it aside manually or the app explicitly cancels it. This is an important aspect Notification method build().

NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)

.setSmallIcon(R.drawable.ic_notification)

.setContentTitle("Notification title")

.setContentText("Message text that the user will see")

.setPriority(NotificationCompat.PRIORITY_DEFAULT)

.setAutoCancel(true);

Pay attention to the method setAutoCancel(true). It tells the system that the notification should be automatically removed from the panel after the user clicks on it. If you do not set this flag, the notification will remain hanging in the curtain until the user brushes it aside manually or the app explicitly cancels it. This is an important aspect UXthat beginners often miss.

โ˜‘๏ธ Check before publication

Completed: 0 / 1

Setting up actions and interactivity

A static notification itself is of little use if it does not allow user to interact with the application. The mechanism PendingIntent serves as a bridge between your application and the notification system, allowing you to perform a pre-arranged action on behalf of your application the moment the user clicks on a button. This could be starting an activity, sending a broadcast intent (Broadcast), or starting a service (Service).

Most often, you want to open a specific application screen when clicked. To do this, a regular Intentis created, indicating the target activity, which is then wrapped in PendingIntent.getActivity. The resulting object is passed to the notification builder via the setContentIntentmethod. It is important to set the flags for the Intent correctly, for example FLAG_ACTIVITY_NEW_TASKso that the activity opens correctly even if the application is completely closed.

In addition to the main click, you can add action buttons directly to the notification body. This allows the user to quickly reply to a message, mark a task completed, or start playing music without opening the application itself. Such actions are also implemented through PendingIntent, but are added to the builder using the method addAction, where the button icon, text label and the intent object itself are specified.

Type PendingIntent Creation method Usage scenario
Activity PendingIntent.getActivity() Opening the application screen when clicked
Broadcast PendingIntent.getBroadcast() Sending a command within the application (for example, "Stop")
Service PendingIntent.getService() Running a background task (downloading a file)
TaskStackBuilder TaskStackBuilder.create() Creating the correct navigation history (Back stack)

โš ๏ธ Attention: Starting from Android 12 (API 31), when creating PendingIntent you must explicitly specify the mutability flag: FLAG_IMMUTABLE or FLAG_MUTABLE. If this is not done, the application will crash when attempting to create a notification. In most cases, it is enough to use FLAG_IMMUTABLE to increase security.

What is TaskStackBuilder?

This is a helper class that allows you to create an artificial stack of activities. If the user clicks on a notification while the app is closed, this class ensures that clicking the back button takes the user through the correct hierarchy of screens rather than simply exiting the app.

Advanced styling and appearance customization

The standard notification view is fine for most simple tasks, but sometimes you need to display more information or use a unique design. The Android support library provides several ready-made styles through the NotificationCompatclass, which significantly expand the display capabilities. The style is applied using the method setStyle() at the builder before calling build().

One โ€‹โ€‹of the most popular is BigTextStyle, which allows you to display large blocks of text hidden by default under the expand button. This is ideal for news feeds or long emails. Another common option is BigPictureStyle, which allows you to show a large image, which is in demand on social networks and galleries. There is also InboxStyle to display a list of events that simulates a mailbox.

For completely unique cases, when standard templates are not enough, developers can create a completely custom layout. This is done using the RemoteViewsclass, which allows you to inflate XML layout and pass it to the notification through the setCustomContentView or setCustomBigContentViewmethods. However, it is worth remembering that custom views have limitations on supported widgets and may look different on devices from different manufacturers.

  • ๐Ÿ“ BigTextStyle: To display long text with the ability to scroll inside a notification.
  • ๐Ÿ–ผ๏ธ BigPictureStyle: To display one large image (profile photo, article cover).
  • ๐Ÿ“ง InboxStyle: For a list of several lines (for example, the last 5 emails or chats).
  • ๐ŸŽต MediaStyle: Specialized style for players with playback control buttons.
๐Ÿ’ก

Using advanced styles makes notifications more informative and attractive, but do not overload them. The user should understand the essence of the message in a second without revealing it completely.

Grouping and refresh management

When an application generates a lot of notifications, they can take over the entire notification panel, annoying the user. To avoid this, there is a grouping mechanism (grouping). You can combine several notifications into one summary group by assigning them the same group key using the setGroup()method. The system will automatically create one summary notification, which, when clicked, will open the list of all messages included in the group.

An existing notification is updated by publishing a new notification with the same ID. The system will not create a duplicate, but will replace the contents of the old notification with a new one. This is actively used to display the progress of file downloads or update the delivery status of a message. When updating, you can change the text, icon, and even actions, while maintaining the position of the notification in the list.

To cancel notifications, use the cancel() notification manager method. You can cancel a specific notification by its ID or clear all notifications of your application at once using cancelAll(). It is important to promptly delete notifications that are no longer relevant, for example, a notification about the completion of a download or a read message, so as not to clutter the user interface.

// Update a notification with the same ID

notificationManager.notify(NOTIFICATION_ID, updatedNotification);

// Cancel a specific notification

notificationManager.cancel(NOTIFICATION_ID);

// Cancel all application notifications

notificationManager.cancelAll();

โš ๏ธ Attention: The interfaces and capabilities of the notification system may differ slightly on smartphones from different manufacturers (Samsung, Xiaomi, Huawei). Some shells may aggressively kill background processes, which will cause the notification to not arrive on time. Always test the notifications on real devices of the target brands.

Frequently asked questions (FAQ)

Why doesn't my notification appear on the screen?

The most common reason is that the notification channel is not configured correctly. Check if the channel has been created with the same ID that you specify in the builder. Also make sure the importance level is set higher if you expect a sound or popup. Don't forget to check the settings of the device itself; the user could manually disable notifications for your application. IMPORTANCE_LOW, if you are expecting a sound or a popup. Don't forget to check your device settings; the user may have manually turned off notifications for your app.

How to make the notification work after rebooting the phone?

Notifications themselves are not saved after a reboot. You need to use a component BroadcastReceiverthat listens to the system event BOOT_COMPLETED. In this receiver, you must restore the necessary data and reschedule the display of notifications using AlarmManager or WorkManager.

Is it possible to change the notification icon dynamically?

Yes, you can change the icon every time the notification is updated. However, the small icon (smallIcon) must be a resource from your application (drawable), and not an external image. For large images, use BigPictureStyle or set a large icon via setLargeIcon()where you can download Bitmap from the network.

What is NotificationListenerService and why do you need it?

This is a special service that allows your application to read and process notifications from other applications. It is used to create smartwatches, launchers or automation applications. It requires special permission to work, which the user must grant manually through the Android security settings.

How to display a progress bar in a notification?

For this, use the method setProgress() of the builder. You pass the max value, the current value, and the indeterminate flag. When updating progress, you create a new notification with new values โ€‹โ€‹and the same ID by calling notify(). When the download is complete, set the progress to 0 or delete the notification.

๐Ÿ“Š Which notification style do you use most often?
Standard (Default)
BigText
BigPicture (Picture)
Inbox (List)
Custom (Custom design)