Notification的使用
一般步骤
使用状态栏通知一般有4个步骤:
1、 通过getSystemService()方法获取NotificationManager服务。
2、 创建一个Notification.Builder对象,并为其设置各种属性。
3、 对Notification.Builder对象设置各种属性和事件信息,构造一个对Notification对象。
4、 通过NotificationManager类的notify()方法将通知发送到状态栏。
NotificationManager
NotificationManager : 是状态栏通知的管理类,负责发通知、清除通知等。
NotificationManager 是一个系统Service,必须通过 getSystemService()方法来获取。
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- public void cancel (int id)
取消通知 - public void cancel (String tag, int id)
取消通知 - public void cancelAll ()
取消所有通知 - public void notify (int id, Notification notification)
发布通知 - public void notify (String tag, int id, Notification notification)
发布通知
Builder对象的方法
getNotification()
API小于16时使用此方法构造一个Notification对象build ()
API大于等于16时使用此方法构造一个Notification对象addAction (int icon, CharSequence title, PendingIntent intent)(在API23过时)
添加按钮addAction (Notification.Action action)(API20)
添加按钮setAutoCancel(boolean autoCancel)
设置点击通知后,状态栏自动删除通知setCategory(String category)(API21)
设置通知类别setColor(int argb)(API21)
设置颜色setContent(RemoteViews views)
设置自定义视图setContentInfo(CharSequence info)
设置信息(即右下方显示的内容)setContentIntent(PendingIntent intent)
设置点击后意图,即打开哪个组件setContentText(CharSequence text)
设置内容setContentTitle(CharSequence title)
设置标题setDefaults(int defaults)
向通知添加声音、闪灯和振动效果的最简单、最一致的方式是使用当前的用户默认设置,使用defaults属性,可以组合,如:setDefaults(Notification.DEFAULT_SOUND|Notification.DEFAULT_VIBRATE)
- Notification.DEFAULT_VIBRATE //添加默认震动提醒 需要 VIBRATE permission
- Notification.DEFAULT_SOUND // 添加默认声音提醒
- Notification.DEFAULT_LIGHTS// 添加默认三色灯提醒
- Notification.DEFAULT_ALL// 添加默认以上3种全部提醒
setDeleteIntent(PendingIntent intent)
设置删除时的意图setExtras(Bundle extras)(API19)
设置数据setFullScreenIntent(PendingIntent intent, boolean highPriority)
设置悬挂式NotificationsetGroup(String groupKey)(API20)
设置该通知组的密匙,即确认为哪一组setGroupSummary(boolean isGroupSummary)(API20)
设置是否为一组通知的汇总setLargeIcon(Icon icon)(API23)
设置大图标setLargeIcon(Bitmap b)
设置大图标setLights(int argb, int onMs, int offMs)
设置三色灯,ledARGB 表示灯光颜色、 ledOnMS 亮持续时间、ledOffMS 暗的时间setLocalOnly(boolean localOnly)(API20)
设置该通知是否应不桥接至其它设备。setNumber(int number)
设置一个数(即右下方显示的内容)setOngoing(boolean ongoing)
设置为true时就不能滑动删除setOnlyAlertOnce(boolean onlyAlertOnce)
设置仅提醒一次setPriority(int pri)(API16)
设置优先级
优先级 | 用户 |
---|---|
MAX | 重要而紧急的通知,通知用户这个事件是时间上紧迫的或者需要立即处理的。 |
HIGH | 高优先级用于重要的通信内容,例如短消息或者聊天,这些都是对用户来说比较有兴趣的。 |
DEFAULT | 默认优先级用于没有特殊优先级分类的通知。 |
LOW | 低优先级可以通知用户但又不是很紧急的事件。 |
MIN | 用于后台消息(例如天气或者位置信息)。最低优先级通知将只在状态栏显示图标,只有用户下拉通知抽屉才能看到内容。 |
setProgress(int max, int progress, boolean indeterminate)(API14)
设置进度条setPublicVersion(Notification n)
设置安全锁屏下的通知setShowWhen(boolean show)(API17)
是否显示时间setSmallIcon(int icon, int level)
设置小图标setSmallIcon(int icon)
设置小图标.setSmallIcon(Icon icon)
设置小图标setSortKey(String sortKey)(API20)
设置排序键setSound(Uri sound, AudioAttributes audioAttributes)(API21)
设置铃声setSound(Uri sound)
设置铃声setSound(Uri sound, int streamType)(在API21废弃)
设置铃声setStyle(Notification.Style style)(API16)
设置样式setSubText(CharSequence text)(API16)
设置第三行的文本setTicker(CharSequence tickerText, RemoteViews views)
设置显示在状态栏的提醒内容(5.0及之后没有效果)setTicker(CharSequence tickerText)
设置显示在状态栏的提醒内容(5.0及之后没有效果)setUsesChronometer(boolean b)(API16)
使用计时器setVibrate(long[] pattern)
设置震动,其中数组的奇数位为暂停时间,偶数位为震动时间setVisibility(int visibility)(API21)
设置可达性- VISIBILITY_PUBLIC 只有在没有锁屏时会显示通知
- VISIBILITY_PRIVATE 任何情况都会显示通知
- VISIBILITY_SECRET 在安全锁和没有锁屏的情况下显示通知
setWhen(long when)
设置显示通知的时间,不设置默认获取系统时间,这个值会在Notification上面显示出来
如果不设置LargeIcon,那么系统会默认将上面的SmallIcon显示在通知选项的最左侧,右下角的小图标将不再显示
notification.flags参数介绍
Notification.FLAG_SHOW_LIGHTS //三色灯提醒,在使用三色灯提醒时候必须加该标志符
Notification.FLAG_ONGOING_EVENT //发起正在运行事件(活动中)
Notification.FLAG_INSISTENT //让声音、振动无限循环,直到用户响应 (取消或者打开)
Notification.FLAG_ONLY_ALERT_ONCE //发起Notification后,铃声和震动均只执行一次
Notification.FLAG_AUTO_CANCEL //用户单击通知后自动消失
Notification.FLAG_NO_CLEAR //只有全部清除时,Notification才会清除 ,不清楚该通知(QQ的通知无法清除,就是用的这个)
Notification.FLAG_FOREGROUND_SERVICE //表示正在运行的服务
PendingIntent
PendingIntent是一个Intent的描述、包装,给予了这个PendingIntent 的组件在指定的事件发生或指定的时间到达时启动Activty、Service或者Broadcast。
PendingIntent contentIntent = PendingIntent.getActivity(context,
requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent contentIntent = PendingIntent.getBroadcast(context,
requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent contentIntent = PendingIntent.getService(context,
requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
FLAG_ONE_SHOT
当前描述的PendingIntent只能被使用一次,然后它就会被自动cancel,如果后续还有相同的PendingIntent,那么他们的send方法就会调用失败。对于通知栏消息来说,如果采用此标记,那么同类的通知只能使用一次,后续的通知单击后将无法打开FLAG_NO_CREATE
当前描述的PendingIntent不会主动创建,如果当前PendingIntent之前不存在,那么getActivity、getService、getBroadcast方法会直接返回null,即获取PendingIntent失败。这个标记很少见,它无法单独使用,因此在日常开发中它并没有太多的使用意义FLAG_CANCEL_CURRENT
如果描述的PendingIntent已经存在,那么它们都会被cancel,然后系统会创建一个新的PendingIntent。对于通知栏消息来说,那些cancel的消息单击后将无法打开。FLAG_UPDATE_CURRENT
当前描述的PendingIntent如果已经存在,那么它们都会被更新,即它们的Intent中的Extras会被替换成最新的
上面4个flag中最经常使用的是FLAG_UPDATE_CURRENT,因为描述的Intent有 更新的时候需要用到这个flag去更新你的描述,否则组件在下次事件发生或时间到达的时候extras永远是第一次Intent的extras。
使用 FLAG_CANCEL_CURRENT也能做到更新extras,只不过是先把前面的extras清除,另外FLAG_CANCEL_CURRENT和 FLAG_UPDATE_CURRENT的区别在于能否新new一个Intent,FLAG_UPDATE_CURRENT能够新new一个 Intent,而FLAG_CANCEL_CURRENT则不能,只能使用第一次的Intent。
此外还需要注意参数: int requestCode
对于FLAG_UPDATE_CURRENT,如果上面的requestCode 为常量,则对于先后出现的若干Notification,则所有对应的Intent里面的extra被更新为最新的,就是全部同一为最后一次的。
相反,如果requestCode每次不一样,则里面的Inent的数据没被更新。
对于FLAG_CANCEL_CURRENT,则只响应最前面的第一条Notifiacation,后面所有的不响应….
自定义Notification
实现自定义Notification的步骤
- 创建RemoteViews对象
- Notification.Builder对象中使用setContent(RemoteViews views)方法
RemoteViews
RemoteViews表示的是一个view结构,它可以在其他进程中显示。由于它在其他进程中显示,为了能够更新它的界面,RemoteViews提供了一组基础的操作用于跨进程更新它的界面
支持类型
在RemoteViews并不支持所有的View类型,支持的所有类型如下:
Layout:
FrameLayout, LinearLayout, RelativeLayout,GridLayout
View:
AnalogClock, Button, Chronometer, ImageButton, ImageView, ProgressBar, TextView, ViewFlipper, ListView, GridView, StackView, AdapterViewFlipper,ViewStub
上面说描述的RemoteViews所支持的所有的View类型,RemoteViews不支持它们的子类以及其他View类型。也就是说RemoteViews中不能使用除了上述列表中以外的View,也无法使用自定义View
常用方法
setTextViewText(int viewId,Charsequence text)
设置TextView的文本setTextViewTextSize(int viewId, int units, float size)
设置TextView的字体大小setTextColor(int viewId, int color)
设置TextView的字体颜色setImageViewResource(int viewId, int srcId)
设置ImageView的图片资源setInt(int viewId, String methodName, int value)
反射调用View对象的参数类型为int的方法setLong(int viewId, String methodName, long value)
反射调用View对象的参数类型为long的方法setBoolean(int viewId, String methodName, boolean value)
反射调用View对象的参数类型为boolean的方法setOnClickPendingIntent(int viewId, PendingIntent pendingIntent)
为View添加单击事件,事件类型只能为PendingIntent
内部机制
RemoteViews的构造方法 public RemoteViews(String packageName, int layoutId),第一个参数是当前应用的包名,第二个参数是待加载的布局文件。
RemoteViews提供了一系列的set方法完成view的设置,这是通过反射完成的调用的。例如方法setInt(int viewId, String methodName, int value)就是反射调用view对象的名称为methodName的方法,传入参数value,同样的还有setBoolean、setLong等。方法setOnClickPendingIntent(int viewId, PendingIntent pi)用来为view添加单击事件,事件类型只能为PendingIntent。
系统对View界面执行一系列的更新操作,即通过set方法提交的,但更新操作不是立即执行(在RemoteViews内部会记录所有的更新操作),而是到RemoteViews被加载后执行
通知和小部件分别由NotificationManager和AppWidgetManager管理,而它们通过Binder分别和SystemServer进程中的NotificationManagerService和AppWidgetManagerService进行通信。所以,布局文件实际上是两个Service加载的,运行在SystemServer进程中。
RemoteViews实现了Parcelable接口,它会通过Binder传递到SystemServer进程,系统会根据RemoteViews中的包名信息获取到应用中的资源,从而完成布局文件的加载。
系统将view操作封装成Action对象,Action同样实现了Parcelable接口,通过Binder传递到SystemServer进程。远程进程通过RemoteViews的apply方法来进行view的更新操作,RemoteViews的apply方法内部则会去遍历所有的action对象并调用它们的apply方法来进行view的更新操作。这样做的好处是不需要定义大量的Binder接口,其次批量执行RemoteViews中的更新操作提高了程序性能。
RemoteViews的apply和reapply方法的区别:apply方法会加载布局并更新界面,而reapply方法则只会更新界面。
setOnClickPendingIntent、setPendingIntentTemplate和setOnClickFillIntent的区别,setOnClickPendingIntent用于给普通的view添加点击事件,但是不能给集合(ListView和StackView)中的view设置点击事件,因为开销太大了。如果需要给ListView和StackView中的item添加点击事件,需要结合setPendingIntentTemplate和setOnClickFillIntent一起使用。
假如报了android.app.RemoteServiceException: Bad notification posted from package ****: Couldn’t expand RemoteViews for:****问题,那么可能不一定是写错了,而是使用了Install Run功能,关闭此功能或每次修改自定义Notification的xml布局文件都要在运行前删除应用 *
TaskStackBuilder(API16)
当我们想要跳转的Activity按返回时返回的是应用的主界面或其他界面,而不是桌面时,可以使用此类来构建一个任务栈
步骤
- 创建TaskStackBuilder对象
- 通过addNextIntent (Intent nextIntent)添加跳转的intent
- 重复第二步,直到完成任务栈的创建
- 通过getPendingIntent()方法获得PendingIntent
- 设置跳转的PendingIntent
创建TaskStackBuilder对象
TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(this);
当Activity设置了android:parentActivityName属性时,使用addParentStack()方法可以直接创建其指定的所有上级进栈(但不包括自己),使用addNextIntentWithParentStack()包括自己及所有上级进栈
例子
TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(this);
Intent intent = new Intent(this,MainActivity.class);
taskStackBuilder.addNextIntent(intent);
Intent intent2 = new Intent(this,SecondActivity.class);
taskStackBuilder.addNextIntent(intent2);
Intent intent3 = new Intent(this,ThirdActivity.class);
taskStackBuilder.addNextIntent(intent3);
int requestCode = (int) SystemClock.uptimeMillis();
remoteViews.setOnClickPendingIntent(R.id.test,
taskStackBuilder.getPendingIntent(requestCode,
PendingIntent.FLAG_UPDATE_CURRENT));
常见Notification类型
普通Notification
略
点击取消显示的Notification
- builder中调用setAutoCancel(true)(Notification需要设置ContentIntent才有效)
无法滑动删除的Notification
- builder中调用setOngoing(true)
拥有按钮的Notification
- builder中使用addAction()添加按钮
折叠式Notification
//设置展开后的视图
notification.bigContentView = remoteViews;
横幅式Notification
- builder对象调用setFullScreenIntent()方法
进度条Notification
- builder对象调用setProgress()方法
BigTextStyle样式的Notification
- 创建Notification.BigTextStyle对象
- 使用setBigContentTitle()设置标题
- 使用bigText()设置正文
- 使用setSummaryText()设置末尾行文本
- 使用setStyle()设置此style对象
BigPictureStyle样式的Notification
- 创建Notification.BigPictureStyle对象
- 使用setBigContentTitle()设置标题
- 使用setSummaryText()设置文本
- 使用bigPicture()设置大图,但是太大会造成OOM
- 使用bigLargeIcon()设置图标
- 使用setStyle()设置此style对象
InboxStyle样式的Notification
- 创建Notification.InboxStyle对象
- 使用setBigContentTitle()设置标题
- 使用addLine()添加行文本,调用n次则生成n行文本
- 使用setSummaryText()设置末尾行文本
- 使用setStyle()设置此style对象
MediaStyle样式的Notification
- builder中使用addAction()添加按钮
- 使用setMediaSession()设置MediaSession.Token对象
- 使用setShowActionsInCompactView()方法设置显示在通知右方的图标 最多三个
- 使用setStyle()设置此style对象
参考资料
Android开发艺术探索
【Android】状态栏通知Notification、NotificationManager详解
Notification中PendingIntent.Flag的应用
Android 通知栏Notification的整合 全面学习 (一个DEMO让你完全了解它)
Android Notification常见样式总结