In what seems to be an annual traditions for Styling Android, we’er going to look at the changes to Notifications in the latest version of Android which is, at the time of writing, Oreo 8.1 (API 27). While there aren’t widespread changes to Notifications as there have been in previous Android versions, there are some significant one, and we’ll start off by looking at Notification Channels.
In the previous article we ported the code from the Nougat Notifications series of articles to Kotlin as a basis for this series, so we’ll use that existing behaviour as our starting point. If we run that on a pre-Oreo device (earlier than 8.0, API 25) then everything is fine, however if we run this on an Oreo device, (either 8.0, API 26 or 8.1, API 27) then the Notifications do not appear. The reason for this is a breaking change to Notifications in 8.0 (API 26) which hasn’t yet been implemented, but is quite prominently displayed within the official documentation for Oreo. Moreover, if we actually look at the code in Android Studio we can see that the Builder constructor that we used for Nougat is actually deprecated – we’ll also get a lint error for this, as well:
This deprecation is because in order to show Notifications on Oreo they must all be classified in to Channels. Channel permits the user greater control over which notifications that they see, and which ones they don’t. From Oreo 8.0 (API 26) onwards, all Notifications must be associated to a channel otherwise they will not be shown. The deprecated Builder constructor that we’re using in the code is the pre-Oreo one which does not support Channels hence it being deprecated. So the solution is to use the newer constructor which instead of a single Context argument, also requires a String which represents a channel ID. So how do we obtain a channel ID?
In order to answer that question, we need to understand what a channel actually is. It is a mechanism where we can logically group different kinds of notifications. In our simple demo app, we only have a single notification type which represents a new message being generated. However for real-world messaging apps, there may be different kinds of notification such as and incoming message, and new contact request, or being mentioned by somebody else. The usefulness of these notification may change from user to user and if we put each in to a different channel then different users have the ability to change the channel settings so they get notifications for the events they are interested in, but do not get spammed by notifications for events that they do no care about.
In order to demonstrate how channels work, we’ll actually create three different channels in our app which represent high priority messages, normal priority ones, and low priority ones. Each message that gets generated will be randomly assigned to one of these channels. OK, this is a little forced, but then the entire concept of this demo app is a little contrived, so we’re just creating a way of showing how this mechanism works.
Once we have these implemented if there is a different message of each type then the user will see this:
Each of the categories uses a different icon so we can see the importance reflected, and the system will order them in terms of priority – the highest priority notifications will be shown above the normal priority ones, which will be above the low priority ones. If the user long taps on a message, they will be presented with the name of the channel which is referred to as a notification category in the UI:
Here the user can turn that category on and off, or can go it to the notification settings for the app which created the notification. If they chose the latter option they are presented with a list of the categories defined for the app:
In this screen they can toggle categories on or off, or tap on individual categories for fine-grained control ver how they are alerted about the notification:
This actually allows the user a lot of flexibility in determining how they wish to be alerted about this notification, even down to whether it is displayed on the lock screen or not. They can even drill down further to change the importance of this category:
All of these settings will take priority over those that we set as defaults when creating the channel. This is really quite a powerful system which allows the user very good control over the notifications are important to them and those which aren’t. Being able to control this makes it for the user to really tailor notifications on their devices.
It is actually really important for apps to support this to do this as many users will quickly become accustomed to being able to control their notifications in Oreo, and if individual apps do not permit the user to control the notifications they are likely to disable notifications altogether for that app, or find an alternative app which does permit good control over notifications. Be sensible in how you categorise notifications to properly allow the user to filter those which are important, or you’ll most likely lose them. For example, if you add inappropriate notifications (such as marketing messages) in to a category that the user may otherwise find really high priority, you risk alienating them if there is no way to opt out of these without also losing the notifications they find important. You risk losing users by getting this wrong.
In the next article we’ll get stuck in to how we actually implement channels. It really isn’t that difficult, but achieving backwards compatibility does require a little effort.
Apologies that there isn’t any code to show for this article as we’ve been concerned with what channels are and why they are important for the user. But the code from the previous article which we’ll be adding channels to, and currently displays the deprecated Builder constructor that we discussed early on in this article, is available here.
© 2017, Mark Allison. All rights reserved.
Copyright © 2017 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.