Notification
Notification 能干什么,那些设计是和Notification相关的;这里直接从官网取图,直接看图;
可以直接回复消息,快捷回复等;
针对一般Notification的样式
The most common parts of a notification are indicated in figure 7 as follows:
- Small icon: This is required and set with setSmallIcon().
- App name: This is provided by the system.
- Time stamp: This is provided by the system but you can override with setWhen() or hide it with setShowWhen(false).
- Large icon: This is optional (usually used only for contact photos; do not use it for your app icon) and set withsetLargeIcon().
- Title: This is optional and set with setContentTitle().
- Text: This is optional and set with setContentText().
setStyle() 抽象类Style 有种实现类,分别是:
1:BigTextStyle 处理大量文案样式;
2: MediaStyle 处理多媒体通知样式;
3: DecoratedCustomViewStyle 自定义包装样式;
4: NessagingStyle 消息样式;
5: BigPictureStyle 展示大图样式;
6: InboxStyle 展示消息在同一个box的样式;
大概步骤:
// Main steps for building a BIG_TEXT_STYLE notification:
// 0. Get your data
// 1. Create/Retrieve Notification Channel for O and beyond devices (26+)
// 2. Build the BIG_TEXT_STYLE
// 3. Set up main Intent for notification
// 4. Create additional Actions for the Notification
// 5. Build and issue the notification
// 根据id,取消对应的notifcation
NotificationManagerCompat notificationManagerCompat =
NotificationManagerCompat.from(getApplicationContext());
notificationManagerCompat.cancel(MainActivity.NOTIFICATION_ID);
简单使用
- Create/Retrieve Notification Channel for O and beyond devices (26+)(必须)
- Build the BIG_TEXT_STYLE(可选)
- Set up main Intent for notification(可选)
- Create additional Actions for the Notification(可选)
- Build and issue the notification(必须)
下面是具体代码 来着Google 官方demo
/*
* Generates a BIG_TEXT_STYLE Notification that supports both phone/tablet and wear. For devices
* on API level 16 (4.1.x - Jelly Bean) and after, displays BIG_TEXT_STYLE. Otherwise, displays
* a basic notification.
*/
private void generateBigTextStyleNotification() {
// Main steps for building a BIG_TEXT_STYLE notification:
// 0. Get your data
// 1. Create/Retrieve Notification Channel for O and beyond devices (26+)
// 2. Build the BIG_TEXT_STYLE
// 3. Set up main Intent for notification
// 4. Create additional Actions for the Notification
// 5. Build and issue the notification
// 0. Get your data (everything unique per Notification).
//通过一个类将数据都封装在这个类中,统一管理
MockDatabase.BigTextStyleReminderAppData bigTextStyleReminderAppData =
MockDatabase.getBigTextStyleData();
// 1. Create/Retrieve Notification Channel for O and beyond devices (26+).
// 在Android O 之后非常必要的操作,这里有个小细节关于在Kotlin中创建channel,
String notificationChannelId =
NotificationUtil.createNotificationChannel(this, bigTextStyleReminderAppData);
// 2. Build the BIG_TEXT_STYLE.
// 使用style 样式
BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle()
// Overrides ContentText in the big form of the template.
// 如果点击展开消息内容的箭头:bigText的内容会覆盖在notification中设置的设置的内容(ContentText);
.bigText(bigTextStyleReminderAppData.getBigText())
// Overrides ContentTitle in the big form of the template.
// 如果点击展开消息内容的箭头:bigContentTitle的内容会覆盖notification中设置的内容(ContentTitle)
.setBigContentTitle(bigTextStyleReminderAppData.getBigContentTitle())
// Summary line after the detail section in the big form of the template.
// Note: To improve readability, don't overload the user with info. If Summary Text
// doesn't add critical information, you should skip it.
// 设置总结消息提示 :<SummaryText 总结> 内容不能过长,太长也会省略为 xxx.xxxxx... 的形式
.setSummaryText(bigTextStyleReminderAppData.getSummaryText());
// 3. Set up main Intent for notification
// (给PendingIntent 绑定的真正 Intent )这里可以使Activity 或者 Service,
// 但是绑定PendingIntent 时需要注意API 的调用(具体事例中有)
// 务必记得 单打开对应的Activity 或者 Service ,有必要执行cancel 掉对应的notification
Intent notifyIntent = new Intent(this, BigTextMainActivity.class);
// When creating your Intent, you need to take into account the back state, i.e., what
// happens after your Activity launches and the user presses the back button.
// There are two options:
// 1. Regular activity - You're starting an Activity that's part of the application's
// normal workflow.
// 2. Special activity - The user only sees this Activity if it's started from a
// notification. In a sense, the Activity extends the notification by providing
// information that would be hard to display in the notification itself.
// For the BIG_TEXT_STYLE notification, we will consider the activity launched by the main
// Intent as a special activity, so we will follow option 2.
// For an example of option 1, check either the MESSAGING_STYLE or BIG_PICTURE_STYLE
// examples.
// For more information, check out our dev article:
// https://developer.android.com/training/notify-user/navigation.html
// Sets the Activity to start in a new, empty task
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent notifyPendingIntent =
PendingIntent.getActivity(
this,
0,
notifyIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
// 4. Create additional Actions (Intents) for the Notification.
// 创建 Actions (Intents) 效果直接看图
// In our case, we create two additional actions: a Snooze action and a Dismiss action.
// Snooze Action.
Intent snoozeIntent = new Intent(this, BigTextIntentService.class);
snoozeIntent.setAction(BigTextIntentService.ACTION_SNOOZE);
PendingIntent snoozePendingIntent = PendingIntent.getService(this, 0, snoozeIntent, 0);
NotificationCompat.Action snoozeAction =
new NotificationCompat.Action.Builder(
R.drawable.ic_alarm_white_48dp,
"Snooze",
snoozePendingIntent)
.build();
// Dismiss Action.
Intent dismissIntent = new Intent(this, BigTextIntentService.class);
dismissIntent.setAction(BigTextIntentService.ACTION_DISMISS);
PendingIntent dismissPendingIntent = PendingIntent.getService(this, 0, dismissIntent, 0);
NotificationCompat.Action dismissAction =
new NotificationCompat.Action.Builder(
R.drawable.ic_cancel_white_48dp,
"Dismiss",
dismissPendingIntent)
.build();
// 5. Build and issue the notification.
// Because we want this to be a new notification (not updating a previous notification), we
// create a new Builder. Later, we use the same global builder to get back the notification
// we built here for the snooze action, that is, canceling the notification and relaunching
// it several seconds later.
// Notification Channel Id is ignored for Android pre O (26).
NotificationCompat.Builder notificationCompatBuilder =
new NotificationCompat.Builder(
getApplicationContext(), notificationChannelId);
GlobalNotificationBuilder.setNotificationCompatBuilderInstance(notificationCompatBuilder);
Notification notification = notificationCompatBuilder
// BIG_TEXT_STYLE sets title and content for API 16 (4.1 and after).
.setStyle(bigTextStyle) // 设置样式
// Title for API <16 (4.0 and below) devices.
.setContentTitle(bigTextStyleReminderAppData.getContentTitle()) //设置未展开时的标题
// Content for API <24 (7.0 and below) devices.
.setContentText(bigTextStyleReminderAppData.getContentText()) // 设置未展开时的内容
.setSmallIcon(R.drawable.ic_launcher) // 设置顶部smallIcon
.setLargeIcon(BitmapFactory.decodeResource( // 设置右侧LargeIcon 注意颜色,白色可就看不到了
getResources(),
R.drawable.ic_action_name1))
.setContentIntent(notifyPendingIntent)
.setDefaults(NotificationCompat.DEFAULT_ALL) // 设置声音 ,震动,默认等
// Set primary color (important for Wear 2.0 Notifications). 这个颜色会同步到smallIcon , action 字体颜色
.setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorAccent))
// SIDE NOTE: Auto-bundling is enabled for 4 or more notifications on API 24+ (N+)
// devices and all Wear devices. If you have more than one notification and
// you prefer a different summary notification, set a group key and create a
// summary notification via
// .setGroupSummary(true)
// .setGroup(GROUP_KEY_YOUR_NAME_HERE)
.setCategory(Notification.CATEGORY_MESSAGE) // 设置消息类型
// Sets priority for 25 and below. For 26 and above, 'priority' is deprecated for
// 'importance' which is set in the NotificationChannel. The integers representing
// 'priority' are different from 'importance', so make sure you don't mix them.
.setPriority(bigTextStyleReminderAppData.getPriority())
// Sets lock-screen visibility for 25 and below. For 26 and above, lock screen
// visibility is set in the NotificationChannel.
.setVisibility(bigTextStyleReminderAppData.getChannelLockscreenVisibility())
.setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL) // 是否展示在桌面icon 上展示徽章 badge
// Adds additional actions specified above.
.addAction(snoozeAction)
.addAction(dismissAction)
.build();
mNotificationManagerCompat.notify(NOTIFICATION_ID, notification);
}
1:应用名 和 时间之间的内容是总结内容,SummaryText;
2: setColor 会影响图标颜色,和 Actions 文字颜色,但是不会影响状态栏的图标;
3: 当有消息时,8.0系统 桌面icon 边上的可以控制展示不展示
val id = "my_channel_01"
val name = getString(R.string.channel_name)
val descriptionText = getString(R.string.channel_description)
val importance = NotificationManager.IMPORTANCE_LOW
val mChannel = NotificationChannel(id, name, importance).apply {
description = descriptionText
setShowBadge(false) //关键代码
}
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(mChannel)
Note :
1:Kotlin 的 创建NotificationCompat.Builder时;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
channelID = "channelID"
var channel = NotificationChannel(channelID, "this is name ", NotificationManager.IMPORTANCE_DEFAULT)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
if (channelID == null) {
//注意这里,如果channelID 为可空类型时,
//不能使用NotificationCompat.Builder(this, channelID) 所以如此处理
builder = NotificationCompat.Builder(this)
} else {
builder = NotificationCompat.Builder(this, channelID!!)
}
2: Android 8.0 之后需要创建Channel,创建Notification需要ChannelID;
// 代码来着Google dome
public static String createNotificationChannel(
Context context,
MockDatabase.MockNotificationData mockNotificationData) {
// NotificationChannels are required for Notifications on O (API 26) and above.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// The id of the channel.
String channelId = mockNotificationData.getChannelId();
// The user-visible name of the channel.
CharSequence channelName = mockNotificationData.getChannelName();
// The user-visible description of the channel.
String channelDescription = mockNotificationData.getChannelDescription();
//NotificationManager.IMPORTANCE_MAX;IMPORTANCE_HIGH;IMPORTANCE_DEFAULT;
//IMPORTANCE_LOW;IMPORTANCE_MIN;IMPORTANCE_NONE;IMPORTANCE_UNSPECIFIED;
int channelImportance = mockNotificationData.getChannelImportance();
boolean channelEnableVibrate = mockNotificationData.isChannelEnableVibrate();
int channelLockscreenVisibility =
mockNotificationData.getChannelLockscreenVisibility();
// Initializes NotificationChannel. 构造(ID, 名字,重要程度)
NotificationChannel notificationChannel =
new NotificationChannel(channelId, channelName, channelImportance);
notificationChannel.setDescription(channelDescription);
notificationChannel.enableVibration(channelEnableVibrate);
// NotificationCompat.VISIBILITY_PRIVATE;VISIBILITY_PRIVATE;VISIBILITY_PUBLIC
notificationChannel.setLockscreenVisibility(channelLockscreenVisibility);
// Adds NotificationChannel to system. Attempting to create an existing notification
// channel with its original values performs no operation, so it's safe to perform the
// below sequence.
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(notificationChannel);
return channelId;
} else {
// Returns null for pre-O (26) devices.
return null;
}
}
3: PendingIntent中的绑定的intent 可以Activity是Service(比如 IntentService 的子类);
从上面贴的示例代码也可以看出;
PendingIntent snoozePendingIntent = PendingIntent.getService(this, 0, snoozeIntent, 0);
PendingIntent notifyPendingIntent =
PendingIntent.getActivity(
this,
0,
notifyIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
但是:按照我的理解,一般setContentIntent 绑定的是Acitivity ,addAction 绑定的是Service
4:取消notification记得使用;不管是在activity 还是service
NotificationManagerCompat notificationManagerCompat =
NotificationManagerCompat.from(getApplicationContext());
// 根据Notification_ID 取消指定的Notification
notificationManagerCompat.cancel(MainActivity.NOTIFICATION_ID);
官方删除Notification如下:
- The user dismisses the notification.
- The user clicks the notification, and you called setAutoCancel() when you created the notification.
- You call cancel() for a specific notification ID. This method also deletes ongoing notifications.
- You call cancelAll(), which removes all of the notifications you previously issued.
- If you set a timeout when creating a notification using setTimeoutAfter(), the system cancels the notification after the specified duration elapses. If required, you can cancel a notification before the specified timeout duration elapses.
Heads-up 效果
抬头通知会在您的应用发出通知时出现,并在片刻后消失,但仍会像往常一样在通知抽屉中显示。
可能触发抬头通知的示例条件包括:
- 用户的活动处于全屏模式(应用程序使用 fullScreenIntent)。
- 该通知具有高优先级,并在运行Android 7.1(API级别25)及更低级别的设备上使用铃声或振动。setDefaults(NotificationCompat.DEFAULT_ALL)
- 通知渠道对运行Android 8.0(API级别26)及更高版本的设备具有高度重要性。setPriority 以及 NotificationChannel(channelId, channelName, channelImportance)
Actions 的相应
// 4. Create additional Actions (Intents) for the Notification.
// In our case, we create two additional actions: a Snooze action and a Dismiss action.
// Snooze Action.
Intent snoozeIntent = new Intent(this, BigTextIntentService.class);
snoozeIntent.setAction(BigTextIntentService.ACTION_SNOOZE);
PendingIntent snoozePendingIntent = PendingIntent.getService(this, 0, snoozeIntent, 0);
NotificationCompat.Action snoozeAction =
new NotificationCompat.Action.Builder(
R.drawable.ic_alarm_white_48dp,
"Snooze",
snoozePendingIntent)
.build();
BigTextIntentService
public class BigTextIntentService extends IntentService {
private static final String TAG = "BigTextService";
public static final String ACTION_DISMISS =
"com.example.android.wearable.wear.wearnotifications.handlers.action.DISMISS";
public static final String ACTION_SNOOZE =
"com.example.android.wearable.wear.wearnotifications.handlers.action.SNOOZE";
private static final long SNOOZE_TIME = TimeUnit.SECONDS.toMillis(5);
public BigTextIntentService() {
super("BigTextIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "onHandleIntent(): " + intent);
if (intent != null) {
final String action = intent.getAction();
if (ACTION_DISMISS.equals(action)) {
handleActionDismiss(); //cancleNotification
} else if (ACTION_SNOOZE.equals(action)) {
handleActionSnooze(); //发送Notification
}
}
}
}
RemoteInuput 类似Reply的
// Create the RemoteInput.
String replyLabel = getString(R.string.reply_label);
RemoteInput remoteInput =
new RemoteInput.Builder(BigPictureSocialIntentService.EXTRA_COMMENT)
.setLabel(replyLabel)
// List of quick response choices for any wearables paired with the phone
.setChoices(bigPictureStyleSocialAppData.getPossiblePostResponses())
.build();
// Pending intent =
// API <24 (M and below): activity so the lock-screen presents the auth challenge
// API 24+ (N and above): this should be a Service or BroadcastReceiver
PendingIntent replyActionPendingIntent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Intent intent = new Intent(this, BigPictureSocialIntentService.class);
intent.setAction(BigPictureSocialIntentService.ACTION_COMMENT);
replyActionPendingIntent = PendingIntent.getService(this, 0, intent, 0);
} else {
replyActionPendingIntent = mainPendingIntent;
}
NotificationCompat.Action replyAction =
new NotificationCompat.Action.Builder(
R.drawable.ic_reply_white_18dp,
replyLabel,
replyActionPendingIntent)
.addRemoteInput(remoteInput)
.build();
// 最后addAction(replyAction) 到Notificationbuilder
BigPictureSocialIntentService 中获取输入的关键代码
/*
* Extracts CharSequence created from the RemoteInput associated with the Notification.
*/
private CharSequence getMessage(Intent intent) {
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
if (remoteInput != null) {
return remoteInput.getCharSequence(EXTRA_COMMENT);
}
return null;
}
补充 Notes:
1:如果多个通道使用Heads-up效果 会导致失效;
2: Beginning with Android 8.1 (API level 27), apps cannot make a notification sound more than once per second. If your app posts multiple notifications in one second, they all appear as expected, but only the first notification per second makes a sound.
8.1 以后每秒只能发生一个Notification;
更多细节参考官网和官方Demo