简介
指 Android 在应用的界面之外显示的消息,旨在向用户提供提醒、来自他人的通信信息或应用中的其他实时信息。用户可以点击通知来打开应用,也可以直接在通知中执行某项操作,比如点击按钮可以切歌,甚至在通知栏上直接回复消息。
显示位置
- 状态栏和通知栏
在状态栏上显示通知图标,在通知栏显示详细内容,用户点击通知栏里面的通知一般会跳转到应用相应页面。 - 屏幕上方
当未锁屏时通知可以显示在屏幕上面,可以伴随着提示音或者震动,提示一会后如果用户没有处理会自动消失 - 锁屏显示
当屏幕锁定时,通知可以显示在锁屏界面上,并且伴随亮屏,用户可根据通知等级控制可显示的通知 - 应用图标
在一些设备上,通知可以显示在应用图标上,一般在右上方显示一个数字代表该应用有多少通知用户未查看,用户可以长按应用图标查看通知列表。
概念
- 渠道:从 Android 8.0(API 级别 26)开始,必须为所有通知分配渠道,否则通知将不会显示。用户可以根据渠道接收想要接收的通知
- 重要程度: Android 7.1(API 级别 25)及更低版本的设备上,每条通知的重要程度均由通知的 priority 决定;在搭载 Android 8.0(API 级别 26)及更高版本的设备上,通知的重要程度由通知发布到的渠道的 importance 决定。通知的重要程度不同,提示用户的方式就不同,重要度越高提示越明显。
- 前台服务的通知:在服务内发送的前台通知,用户无法移除,除非关闭服务或者在服务内部关闭该通知
- 勿扰模式:从 Android 5.0(API 级别 21)开始,用户可以启用勿扰模式,来控制被打扰的情况,指定可以打扰的类型。
简单使用
- 创建通道
@TargetApi(Build.VERSION_CODES.O)
public static void createNotificationChannel(Context ctx, String channelId, String channelName, String channelDes) {
NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription(channelDes);
channel.setSound(null, null);
channel.enableLights(true);
channel.setLightColor(Color.RED);
channel.setShowBadge(true);
NotificationManager notifyMgr = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
notifyMgr.createNotificationChannel(channel);
}
- 创建通知
//用户点击通知的意图
Intent intent = new Intent(mContext, MainActivity.class);
//通知中的交互都用延迟意图 PendingIntent
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
//添加按钮点击意图,在通知里面的按钮点击必须都用过broadcast,在broadcast处理点击事件
Intent btnIntent = new Intent(mContext, MusicReceiver.class);
btnIntent.setAction("com.dean.smartapp.broadcast.music");
btnIntent.putExtra("data", "notification data");
PendingIntent btnPendingIntent = PendingIntent.getBroadcast(mContext, 0, btnIntent, 0);
//使用之前的通道 NotifyUtils.NOTIFY_CHANNEL_MUSIC 创建一个通知,如果较低版本不需要通道,NotificationCompat会自动适配
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, NotifyUtils.NOTIFY_CHANNEL_MUSIC);
builder.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("通知标题")
.setContentText("这是一条通知的内容")
//设置通知的展开内容
.setStyle(new NotificationCompat.BigTextStyle().bigText("这是通知的扩展内容,可以是文本扩展或者其他扩展内容,在通知栏可以直接查看"))
//设置通知的重要等级以影响通知用户的方式
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
//设置用户点击通知后的意图
.setContentIntent(pendingIntent)
//用户点击后自动移除
.setAutoCancel(true)
//添加按钮,默认最多只能添加三个按钮,而不影响通知本身的正常点击跳转Activity
.addAction(R.mipmap.ic_launcher, "通知按钮1", btnPendingIntent)
.addAction(R.mipmap.ic_launcher, "通知按钮2", btnPendingIntent)
.addAction(R.mipmap.ic_launcher, "通知按钮3", btnPendingIntent);
- 显示通知
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(mContext);
notificationManagerCompat.notify(0, builder.build());
在通知栏直接输入文本
在Android 7.0(API 级别 24)允许用户直接在通知中输入文本,然后会直接提交给应用,而不必打开 Activity。比如聊天软件可以在通知栏直接回复(对比了iOS后,哎,效果天壤之别,希望谷歌能够优化吧)
首先创建RemoteInput用来显示输入框,接收用户输入的文字
RemoteInput remoteInput = new RemoteInput.Builder("Key值用来取出用户输入的数据").setLabel("输入框默认文字").build();
使用Broadcast来接收文字
Intent inputIntent = new Intent(mContext, MusicReceiver.class);
inputIntent.setAction("com.dean.smartapp.broadcast.music");
inputIntent.putExtra("data", "notification data");
PendingIntent inputPendingIntent = PendingIntent.getBroadcast(mContext, 0, inputIntent,PendingIntent.FLAG_UPDATE_CURRENT);
创建action
NotificationCompat.Action action = new NotificationCompat.Action.Builder(R.mipmap.ic_launcher, "按钮名称", inputPendingIntent)
.addRemoteInput(remoteInput).build();
Intent intent = new Intent(mContext, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, NotifyUtils.NOTIFY_CHANNEL_MUSIC);
builder.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("通知标题")
.setContentText("这是一条通知的内容")
.setContentIntent(pendingIntent)
.setAutoCancel(true)
//将action添加到通知上
.addAction(action);
显示通知
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(mContext);
notificationManagerCompat.notify(0, builder.build());
最后在Receiver中接收文字并且处理,如果需要在通知上显示用户新输入的文字,即发送一个新通知
注意发送通知的flag要和之前一样,用来覆盖之前的通知
public class MusicReceiver extends BroadcastReceiver {
private static final String LOG_TAG = MusicReceiver.class.getSimpleName();
@Override
public void onReceive(Context context, Intent intent) {
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
if (remoteInput != null) {
Log.d(LOG_TAG, "用户通知栏输入 data = " + remoteInput.getCharSequence("a"));
}
}
}
自定义视图
可以使用setCustomContentView和setCustomBigContentView来为通知设置自定义视图,在通知中可以通过长按来切换这两种样式
Notification自定义view使用RemoteViews
RemoteViews smallRemoteViews = new RemoteViews(mContext.getPackageName(), R.layout.notification_small_layout);
RemoteViews bigRemoteViews = new RemoteViews(mContext.getPackageName(), R.layout.notification_big_layout);
Notification customNotification = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setStyle(new NotificationCompat.DecoratedCustomViewStyle())
.setCustomContentView(smallRemoteViews )
.setCustomBigContentView(bigRemoteViews)
.build();
运行效果
添加发送人
在Android P版本以上需要Person来让通知达到最佳呈现,即谁发送了这个通知,它在不支持的设备上无效。
//先创建一个Person
Person person = new Person.Builder()
.setName("胡汉三")
.setIcon(IconCompat.createWithResource(mContext, R.mipmap.ic_launcher))
.build();
//在创建MessaginStyle,如果多人,可以使用setGroupConversation标记为一个组
NotificationCompat.MessagingStyle style = new NotificationCompat.MessagingStyle(person);
style.addMessage("这是胡汉三发送的通知", System.currentTimeMillis(), person);
style.setConversationTitle("胡汉三发送通知啦");
将他设置给notification 正常显示通知即可
NotificationCompat.Builder.setStyle(style)
其他功能
- 关于渠道,应用应该为一类的通知开启单独的渠道,以便用户可以根据渠道管理来控制应用中的通知
- 同一类通知可以添加分组
NotificationCompat.Builder.setGroup(GROUP_KEY_WORK_EMAIL)
为分组添加描述
NotificationCompat.Builder.setStyle(new NotificationCompat.InboxStyle()
.addLine("Alex Faarborg Check this out")
.addLine("Jeff Chang Launch Party")
.setBigContentTitle("2 new messages")
.setSummaryText("dean"))
NotificationCompat.Builder.setGroupSummary(true)
- Builder的setStyle()可以为通知设置许多展开后的样式,比如展开大文本、展开大图,甚至是音乐播放器的一些播控,但是谷歌提供的默认样式不一定适用,这时可用自定义样式来处理
- notificationManagerCompat.notify显示通知时可以使用相同的id来覆盖之前的通知,为了避免提示用户的方式多次发生,可以使用setOnlyAlertOnce()来设置只提醒一次。
- 移除通知的方式除了用户处理,代码中可通过cancelAll() 来取消所有通知,或者使用setTimeoutAfter() 为通知设置超时,当时间到了自动消失
- 可以通过setVisibility()来控制通知在锁屏时的显示内容。取值有三个:
VISIBILITY_PUBLIC 显示通知的完整内容。
VISIBILITY_SECRET 不在锁定屏幕上显示该通知的任何部分。
VISIBILITY_PRIVATE 显示基本信息,例如通知图标和内容标题,但隐藏通知的完整内容
- 需要显示进度条时可以使用setProgress
builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false);
然后通过ID发送相同的通知来更新进度
如果完成后需要取消进度条,需要设置
.setProgress(0,0,false);
- 关于PendingIntent最后一个参数FLAG
FLAG_ONE_SHOT:获取的PendingIntent只能使用一次
FLAG_NO_CREATE:利用FLAG_NO_CREAT获取的PendingIntent,若描述的Intent不存在则返回NULL值
FLAG_CANCEL_CURRENT:如果描述的PendingIntent已经存在,则在产生新的Intent之前会先取消掉当前的
FLAG_UPDATE_CURRENT:能够新new一个 Intent