问题
I cannot change this feeling: again, the Android developers came up with something new and leave everybody in the dark about how they would think the feature is used.
I am talking about Notification Channels in Android O.
For years I have been using the compatibility support libraries to avoid dealing with specific platform details. Namely: NotificationCompat
.
Now, the Builder
requires me to supply a notification channel id, which is nice, but completely leaves me alone with creating such a channel. I cannot find any compat support for creating channels. Nor can I find a reasonable way to create them at the right point.
The docs simply state that it should be done "somewhere" and "probably not when issuing a notification". But what exactly am I supposed to do? I hate writing version specific stuff for simple tasks - that's why I use the compat libraries.
Does anybody have a suggestion on how to handle it? Is it "expensive" to do the creating each and every time when I want a notification to be displayed?
回答1:
This is my solution to generate notifications on Android O and maintain backward compatibility:
String idChannel = "my_channel_01";
Intent mainIntent;
mainIntent = new Intent(context, LauncherActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, mainIntent, 0);
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel mChannel = null;
// The id of the channel.
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, null);
builder.setContentTitle(context.getString(R.string.app_name))
.setSmallIcon(getNotificationIcon())
.setContentIntent(pendingIntent)
.setContentText(context.getString(R.string.alarm_notification) + ManagementDate.getIstance().hourFormat.format(getAlarm(context, 0)));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mChannel = new NotificationChannel(idChannel, context.getString(R.string.app_name), importance);
// Configure the notification channel.
mChannel.setDescription(context.getString(R.string.alarm_notification));
mChannel.enableLights(true);
mChannel.setLightColor(Color.RED);
mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
mNotificationManager.createNotificationChannel(mChannel);
} else {
builder.setContentTitle(context.getString(R.string.app_name))
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setColor(ContextCompat.getColor(context, R.color.transparent))
.setVibrate(new long[]{100, 250})
.setLights(Color.YELLOW, 500, 5000)
.setAutoCancel(true);
}
mNotificationManager.notify(1, builder.build());
回答2:
It's not as expensive as you think! All you need to do is creating a notification channel and bind it to notification.
You can solve this in two ways but for both of them you need to create a notification channel with a specific channel id.
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String id = "my_channel_01";
int importance = NotificationManager.IMPORTANCE_LOW;
NotificationChannel mChannel = new NotificationChannel(id, name,importance);
mChannel.enableLights(true);
mNotificationManager.createNotificationChannel(mChannel);
First way is to set channel for notification in constructor:
Notification notification = new Notification.Builder(MainActivity.this , id).setContentTitle("Title");
mNotificationManager.notify("your_notification_id", notification);
Second way is to set the channel by Notificiation.Builder.setChannelId()
Notification notification = new Notification.Builder(MainActivity.this).setContentTitle("Title").
setChannelId(id);
mNotificationManager.notify("your_notification_id", notification);
Hope this helps
回答3:
Here is an alternative solution that uses reflection to create the Notification Channel so you can set a compileSdkVersion
of lower than 26.
private void createNotificationChannel(NotificationManager notificationManager) {
// Channel details
String channelId = "myChannelId";
String channelName = "Notifications";
// Channel importance (3 means default importance)
int channelImportance = 3;
try {
// Get NotificationChannel class via reflection (only available on devices running Android O or newer)
Class notificationChannelClass = Class.forName("android.app.NotificationChannel");
// Get NotificationChannel constructor
Constructor<?> notificationChannelConstructor = notificationChannelClass.getDeclaredConstructor(String.class, CharSequence.class, int.class);
// Instantiate new notification channel
Object notificationChannel = notificationChannelConstructor.newInstance(channelId, channelName, channelImportance);
// Get notification channel creation method via reflection
Method createNotificationChannelMethod = notificationManager.getClass().getDeclaredMethod("createNotificationChannel", notificationChannelClass);
// Invoke method on NotificationManager, passing in the channel object
createNotificationChannelMethod.invoke(notificationManager, notificationChannel);
// Log success to console
Log.d("MyApp", "Notification channel created successfully");
}
catch (Exception exc) {
// Log exception to console
Log.e("MyApp", "Creating notification channel failed", exc);
}
}
Then, when you're building your notifications, simply call the .setChannelId()
method of NotificationCompat.Builder
:
builder.setChannelId("myChannelId");
Note: You need to update your appcompat-v7
library to version 26.x.x
in build.gradle
:
compile 'com.android.support:appcompat-v7:26.1.0'
回答4:
If you want to support previous versions of Android (< Oreo). We may wrap the NotificationManager
to create and build Notification.Builder
instance in a NotificationHelper
like this:
/**
* Helper class to manage notification channels, and create notifications.
* <p>
* Created by teocci.
*
* @author teocci@yandex.com on 2018-Oct-02
*/
public class NotificationHelper extends ContextWrapper
{
public static final String NOTIFICATION_CHANNEL_PRIMARY = "notification_channel_primary";
public static final int NOTIFICATION_ID_PRIMARY = 1100;
private NotificationManager manager;
/**
* Registers notification channels, which can be used later by individual notifications.
*
* @param ctx The application context
*/
public NotificationHelper(Context ctx)
{
super(ctx);
// For API 26+ create notification channels
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_PRIMARY,
getString(R.string.channel_name),
NotificationManager.IMPORTANCE_DEFAULT
);
channel.setLightColor(Color.BLUE);
channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
channel.setDescription(getString(R.string.channel_description));
getManager().createNotificationChannel(channel);
}
}
/**
* Cancel a previously shown notification. If it's transient, the view
* will be hidden. If it's persistent, it will be removed from the status
* bar.
*
* @param id The ID of the notification
*/
public void remove(int id){
manager.cancel(id);
}
/**
* Get a notification of type 1
* <p>
* Provide the builder rather than the notification it's self as useful for making notification
* changes.
*
* @return the builder as it keeps a reference to the notification (since API 24)
*/
public Notification getNotification()
{
return getNotification(getTitle(), getBody()).build();
}
/**
* Get a notification of type 1
* <p>
* Provide the builder rather than the notification it's self as useful for making notification
* changes.
*
* @param title the title of the notification
* @param body the body text for the notification
* @return the builder as it keeps a reference to the notification (since API 24)
*/
public Notification.Builder getNotification(String title, String body)
{
Notification.Builder builder = new Notification.Builder(getApplicationContext())
.setOngoing(true) // Persistent notification!
.setAutoCancel(true)
.setTicker(title)
.setContentTitle(title)
.setContentText(body)
.setSmallIcon(getSmallIcon());
// Set the Channel ID for Android O.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(NOTIFICATION_CHANNEL_PRIMARY); // Channel ID
}
return builder;
}
/**
* Send a notification.
*
* @param id The ID of the notification
* @param notification The notification object
*/
public void notify(int id, Notification.Builder notification)
{
getManager().notify(id, notification.build());
}
/**
* Get the notification manager.
* <p>
* Utility method as this helper works with it a lot.
*
* @return The system service NotificationManager
*/
private NotificationManager getManager()
{
if (manager == null) {
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
}
return manager;
}
/**
* Get the small icon for this app
*
* @return The small icon resource id
*/
private int getSmallIcon()
{
return R.drawable.ic_smart_audio_noti_icon;
}
/**
* Get the notification title for this app
*
* @return The notification title as string
*/
private String getTitle()
{
return getString(R.string.notification_title);
}
/**
* Get the notification content for this app
*
* @return The notification content as string
*/
private String getBody()
{
return getString(R.string.notification_content);
}
}
Then we can use it easily like this:
@Override
public void onCreate()
{
...
notificationHelper = new NotificationHelper(this);
notificationHelper.notify(NotificationHelper.NOTIFICATION_ID_PRIMARY, "App is running");
...
}
@Override
public void onDestroy()
{
notificationHelper.remove(NotificationHelper.NOTIFICATION_ID_PRIMARY)
}
回答5:
If your notification code has the same structure every time so you should create a static method and pass all what you want and put the code which check the API Level inside this method.
回答6:
Its pretty simple to work with NotificationChannnel.
NotificationChannel actually group multiple notifications into channels. It basically gives more control of the notification behavior to the user. You can read more about Notification Channel and its implementation at Working with Notification Channel | With Example
Creating Notification Channel
// This is the Notification Channel ID. More about this in the next section
public static final String NOTIFICATION_CHANNEL_ID="channel_id";
//User visible Channel Name
public static final String CHANNEL_NAME="Notification Channel";
// Importance applicable to all the notifications in this Channel
int importance=NotificationManager.IMPORTANCE_DEFAULT;
//Notification channel should only be created for devices running Android 26
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, CHANNEL_NAME, importance);
//Boolean value to set if lights are enabled for Notifications from this Channel
notificationChannel.enableLights(true);
//Boolean value to set if vibration is enabled for Notifications from this Channel
notificationChannel.enableVibration(true);
//Sets the color of Notification Light
notificationChannel.setLightColor(Color.GREEN);
//Set the vibration pattern for notifications. Pattern is in milliseconds with the format {delay,play,sleep,play,sleep...}
notificationChannel.setVibrationPattern(new long[]{500,500,500,500,500});
//Sets whether notifications from these Channel should be visible on Lockscreen or not
notificationChannel.setLockscreenVisibility(
Notification.VISIBILITY_PUBLIC);
}
// Creating the Channel
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(notificationChannel);
Now while creating the Notification just pass the Channel ID to the Notification Builder constructor as shown below
//We pass the unique channel id as the second parameter in the constructor
NotificationCompat.Builder notificationCompatBuilder=new NotificationCompat.Builder(this,NOTIFICATION_CHANNEL_ID);
//Title for your notification
notificationCompatBuilder.setContentTitle("This is title");
//Subtext for your notification
notificationCompatBuilder.setContentText("This is subtext");
//Small Icon for your notificatiom
notificationCompatBuilder.setSmallIcon(R.id.icon);
//Large Icon for your notification
notificationCompatBuilder.setLargeIcon( BitmapFactory.decodeResource(getResources(),R.id.icon));
notificationManager.notify( NOTIFICATION_ID,notificationCompatBuilder.build());
WIth this above notification becomes a part of the Notification Channel created in the first step and its behavior will now be with respect to the Channel Settings
来源:https://stackoverflow.com/questions/45015803/android-o-notification-channels-and-notificationcompat