Notification简介
通知是在常规UI界面之外向用户展示消息的工具,当系统发出通知时,它会以图表的形式显示在状态栏中。此时打开通知栏,就可以看到通知的详细信息了。创建通知由Notification.Builder类来控制(API 11添加)。另外,v4的支持库也提供了创建通知的类 NotificationCompat.Builder
。在API 11 之前,通知的创建由new Notification()
直接创建,现在不建议使用了。
创建Notification
创建通知通过NotificationCompat.Builder
,创建完成之后,调用NotificationCompat.Builder.build()
方法获取Notification对象,此时通知已经创建好了,下一步发出通知使用NotificationManager.notify()
就可以将通知发送出去了。
创建通知的时候可以在Builder中对通知进行设置,包括图标,标题,点击响应等等。有三个基本参数是必须要包含的:
小图标,由
setSmallIcon()
设置
标题,由setContentTitle()
设置
详细文本,由setContentText()
设置
下面是一个通知的例子,基本上包含了常用的各项设置:
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_action_new) //设置小图标,用于状态栏左上角显示
.setContentTitle("Notification Title") //设置标题
.setContentText("Notification content text.")
.setContentInfo("Content info")
.setSubText("sub text")
.setTicker("ticker...") //通知到来时状态栏闪过的信息,API21以后不再显示
.setDefaults(NotificationCompat.DEFAULT_ALL)//设置默认的灯光,提示音和振动,可选值:DEFAULT_ALL,DEFAULT_SOUND,DEFAULT_VIBRATE,DEFAULT_LIGHTS
// .setLights()
// .setSound()
// .setVibrate()
.setNumber(10) //已经被 setSubText取代,显示在时间下方的内容
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)//5.0以后添加
.setWhen(System.currentTimeMillis()) //设置通知上显示的时间
.setShowWhen(true) //通知是否显示时间
.setUsesChronometer // 设置是否显示时钟表示时间
.setChronometerCountDown(false); // 设置时钟是否为倒计时
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.largeicon)) //设置大图标
.setPriority(NotificationCompat.PRIORITY_MAX) //设置等级,可选值有PRIORITY_MIN(-2),PRIORITY_LOW(-1),PRIORITY_DEFAULT(0),PRIORITY_HIGH(1),PRIORITY_MAX(2),默认为0
.setOngoing(false) //设置是否为正在进行的通知。设置为true表示有相关动作正在执行,比如播放音乐。ongoing状态的通知是不会自动消失,也不能手动清除的。除非调用Manager的cancel方法
.setAutoCancel(true) //是否自动消失,true表示响应点击之后自动消失。
.build(); //API16添加,API11使用getNotification()
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.notify(1, notification);
setVisibility
方法有以下可选值:
-
VISIBILITY_PUBLIC
任何情况下都显示通知的完整内容。 -
VISIBILITY_SECRET
不会在锁定屏幕上显示此通知的任何部分。 -
VISIBILITY_PRIVATE
显示通知图标和内容标题等基本信息,但是隐藏通知的完整内容。
设置 VISIBILITY_PRIVATE 后,还可以通过 setPublicVersion() 提供其中隐藏了某些详细信息的替换版本通知内容。
PendingIntent
为通知设定点击事件,需要使用PendingIntent实现。与Intent相比,PendingIntent表示一种特定的处于等待状态,即将发生的一种状态,而Intent则是马上发生的。PendingIntent可以表示三种意图:
- getActivity(Context context, int requestCode, Intent intent, int flags)
- getService(Context context, int requestCode, Intent intent, int flags)
- getBroadcast(Context context, int requestCode, Intent intent, int flags)
requestCode
表示PendingIntent发送方的请求码,它会对PendingIntent的匹配产生影响,当PendingIntent包含的Intent相同,而且requestCode也相同,系统就为认为这是同样的PendingIntent(Extras不影响)。
flags
常用的值有四个:
-
FLAG_ONE_SHOT
表示该PendingIntent只能被使用一次,使用完之后就自动cancel。 -
FLAG_NO_CREATE
不会主动创建PendingIntent,如果之前不存在该PendingIntent,get方法返回null,调用失败。 -
FLAG_CANCEL_CURRENT
当前PendingIntent如果已经存在了,那么cancel掉存在的,然后重新创建一个。 -
FLAG_UPDATE_CURRENT
当前PendingIntent如果已经存在了,它们都会被更新,替换成新的Extras。
我们使用notify发送通知的时候,如果id相同,会被认为是同一个通知,更新通知的状态。如果发送一系列id不同,内容相同的通知(包括同样的PendingIntent),这时候点击事件就会根据不同的flag做出不同的判断了。
系统会认为这一系列通知的PendingIntent是同样的,所以如果flag是FLAG_ONE_SHOT,第一个点击的通知会响应事件,剩余的通知在点击的时候就不会有动作了,因为PendingIntent已经被cancel。如果flag是FLAG_CANCEL_CURRENT,那么,每次发送一个通知,系统就会发现PendingIntent已经存在了,于是cancel掉存在的PendingIntent,再生成一个新的,只能给自己用,所以只有最后一个会被响应。如果是FLAG_UPDATE_CURRENT,每发送一条,它都会更新当前存在的所有PendingIntent,并替换为最新的Extras,所以,每个通知都会正常响应。
为通知设置事件,通常情况下这两个参数都设置为0就可以了:
Intent intent = new Intent(this, SplashActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0 , intent, 0);
builder.setContentIntent(pi)
设置PendingIntent有三个方法:
-
setContentIntent
点击通知内容 -
setDeleteIntent()
通知被清除时 -
setFullScreenIntent()
全屏事件的Intent,比如在通话时。设置了该项,通知会以浮动的形式闪出
浮动通知是5.0新加的功能,如果通知的优先级设置较高,或者设置了setFullScreenIntent
,通知到来的时候手机处于活动状态(点亮屏幕且未锁屏),这是通知会从顶部自动闪出,并且可以响应点击。
事件进阶-TaskStackBuilder
Android中使用任务栈来管理Activity,这个应该都很清楚了,现在考虑这么一种情况:通过点击通知栏打开一个Activity,这时候,通过Back返回,就会销毁当前Activity,直接返回桌面了,如果我们想返回该应用的首页,而不是退出,就要用到TaskStackBuilder。
我们先看一下TaskStackBuilder的使用方法:
Intent intent = new Intent(this, SplashActivity.class);// 构建一个指向SplashActivity.class的Intent
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);//获取TaskStackBuilder
stackBuilder.addParentStack(SplashActivity.class)
stackBuilder.addNextIntent(intent);
PendingIntent pi2 = stackBuilder.getPendingIntent(0,0);
首先通过TaskStackBuilder.create(this)
创建一个任务栈,下一步方法是addParentStack
,这个方法比较奇葩,我们这里指定的是SplashActivity.class
,实际上它添加的并不是SplashActivity
。它需要与Manifest中的对应Activity的parentActivityName
属性结合使用。
SplashActivity
指定了它的父Activity为DrawableActivity
,所以我们调用addParentStack(SplashActivity.class)
之后,此时返回栈中只是添加了DrawableActivity
addNextIntent
用来继续向返回栈添加Activity,这里才将SplashActivity
添加进来。当然我们也可以继续创建指向其他Activity的Intent,使用addNextIntent
向返回栈中添加新的Activity,最后添加的Activity处于最顶层,依次向下。(实际上addParentStack
并不是必须的,系统使用addNextIntent
添加Activity进栈时,仍然会读取它的android:parentActivityName
并添加对应的父Activity。另外,请不要对被设为parentActivity的Activity再设置android:parentActivityName
,会导致ANR)
使用TaskStackBuilder之后,不能根据intent来创建PendingIntent了,需要使用getPendingIntent
方法,获取到之后设置给Notification,这样就实现了指定返回Activity的功能。
为Activity指定任务栈
上面介绍了创建任务栈并管理其中的Activity,从而实现返回指定Activity的功能。但是,有时候我们需要的功能很简单,点击通知打开Activity,按下Back键返回桌面。此时,如果Activity所在的应用处于开启状态,新开启的Activity会直接添加到当前应用的栈中,所以按下Back之后返回的是应用而不是桌面。
要实现这种功能很简单,为新建的Activity创建新的任务栈就可以了。
首先设置要启动的Activity属性:
......
android:taskAffinity="" //指定任务栈的Affinity,与Intent的NEW_TASK相结合,在新的任务栈启动
android:excludeFromRecents="true">//不显示在最近任务列表
然后:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
再设置PendingIntent给通知就可以了。FLAG_ACTIVITY_CLEAR_TASK
表示清空要启动的Activity所处的任务栈,确保android:taskAffinity
指定的值唯一的情况下可以不设置。
其他常用设置
进度条通知
使用setProgress(max, progress, false)
来设置及进度条通知,并更新进度。第三个参数设置为true表示循环滚动不显示准确进度的进度条。注意进度条与subContent不能同时设置,否则进度条不能显示。-
设置样式
setStyle()
系统已经提供了几个样式给我们使用,有
BigPictureStyle
,BigTextStyle
,MessagingStyle
,InboxStyle
等。
自定义外观
我们可以通过RemoteView来对通知栏进行自定义View的设置。有四个相关方法
setContent
设置普通视图,高度限制为 64 dp
setCustomContentView
设置普通视图,高度限制为 64 dp
setCustomBigContentView()
设置扩展视图,高度可以扩展到256dp
setCustomHeadsUpContentView()
设置浮动通知视图