通知信息是状态栏中最常用的功能之一。根据用户是否拉下下拉卷帘,通知信息表现为一个位于状态栏的图标,或在下拉卷帘中的一个条目。另外,通知信息还可以在其添加入状态栏之时发出声音,以提醒用户注意查看。通知信息即可以表示一条事件,如新的短消息到来、出现了一条未接来电等,也可以用来表示一个正在后台持续进行着的工作,如正在下载某一文件、正在播放音乐等。
#### 1.通知信息的发送
任何使用者都可以通过NotificationManager所提供的接口向状态栏添加一则通知信息。通知信息的详细内容可以通过一个Notification类的实例来描述。
Notification类中包含如下几个用于描述通知信息的关键字段。
- icon,一个用于描述一个图标的资源id,用于显示在状态栏之上。每条通知信息必须提供一个有效的图标资源,否则此信息将会被忽略。
- iconLevel,如果icon所描述的图标资源存在level,那么iconLevel则用于告知状态栏将显示图标资源的那一个level。
- number,一个int型变量用于表示通知数目。例如,当有3条新的短信时,没有必要使用三个通知,而是将一个通知的number成员设置为3,状态栏会将这一数字显示在通知图标上。
- contentIntent,一个PendingIntent的实例,用于告知状态栏当在下拉卷帘中点击本条通知时应当执行的动作。contentIntent往往用于启动一个Activity以便让用户能够查看关于此条通知的详细信息。例如,当用户点击一条提示新短信的通知时,短信应用将会被启动并显示短信的详细内容。
- deleteIntent,一个PendingIntent的实例,用于告知状态栏当用户从下拉卷帘中删除本条通知时应当执行的动作。deleteIntent往往用在表示某个工作正在后台进行的通知中,以便当用户从下拉卷帘中删除通知时,发送者可以终止此后台工作。
- tickerText,一条文本。当通知信息被添加时,状态栏将会在其上逐行显示这条信息。其目的在于使用户无需进行卷帘下拉操作即可从快速获取通知的内容。
- fullScreenIntent,一个PendingIntent的实例,用于告知状态栏当此条信息被添加时应当执行的动作,一般这一动作是启动一个Activity用于显示与通知相关的详细信息。fullScreenIntent其实是一个替代tickerText的设置。当Notification中指定了fullScreenIntent时,StatusBar将会忽略tickerText的设置。因为这两个设置的目的都是为了让用户可以在第一时间了解通知的内容。不过相对于tickerText,fullScreenIntent强制性要明显得多,因为它将打断用户当前正在进行的工作。因此fullScreenIntent应该仅用于通知非常重要或紧急的事件,比如说来电或闹钟。
- contentView/bigContentView,RemoteView的实例,可以用来定制通知信息在下拉卷帘中的显示形式。一般来讲,相对于contentView,bigContentView可以占用更多空间以显示更加详细的内容。状态栏将根据自己的判断选择将通知信息显示为contentView或是bigContentView。
- sound与audioStreamType,指定一个用于播放通知声音的Uri及其所使用的音频流类型。在默认情况下,播放通知声音所用的音频流类型为STREAM\_NOTIFICATION。
- vibrate,一个float数组,用于描述震动方式。
- ledARGB/ledOnMS/ledOffMS,指定当此通知被添加到状态栏时设备上的LED指示灯的行为,这几个设置需要硬件设备的支持。
- defaults,用于指示声音、震动以及LED指示灯是否使用系统的默认行为。
- flags,用于存储一系列用于定制通知信息行为的标记。通知信息的发送者可以根据需求在其中加入这样的标记:FLAG\_SHOW\_LIGHTS要求使用LED指示灯,FLAG\_ONGOING\_EVENT指示通知信息用于描述一个正在进行的后台工作,FLAG\_INSISTENT指示通知声音将持续播放直到通知信息被移除或被用户查看,FLAG\_ONLY\_ARLERT\_ONCE指示任何时候通知信息被加入到状态栏时都会播放一次通知声音,FLAG\_AUTO\_CANCEL指示当用户在下拉卷帘中点击通知信息时自动将其移出,FLAG\_FOREGROUND\_SERVICE指示此通知用来表示一个正在以foreground形式运行的服务。
- priority,描述了通知的重要性级别。通知信息的级别从低到高共分为MIN(-2)、LOW(-1)、DEFAULT(0)以及HIGH(1)四级。低优先级的通知信息有可能不会被显示给用户,或显示在通知列表中靠下的位置。
在随后的讨论中将会详细介绍这些信息如何影响通知信息的显示与行为。
当通知信息的发送者根据需求完成了Notification实例的创建之后,便可以通过NotificationManager.notify()方法将通知显示在状态栏上。
notify()方法要求通知信息的发送者除了提供一个Notification实例之外,还需要提供一个字符串类型的参数tag,以及int类型的参数id,这两个参数一并确定了信息的意图。当一条通知信息已经被提交给NotificationManager.notify()并且仍然显示在状态栏中时,它将会被新提交的拥有相同意图(即相同的tag以及相同的id)通知信息所替换。
参考NotificationManager.notify()方法的实现:
**NotificationManager.java-->NotificationManager.notify()**
```
public void notify(String tag, int id,Notification notification)
{
int[]idOut = new int[1];
// **① 获取NotificationManagerService的Bp端代理**
INotificationManager service = getService();
// **② 获取信息发送者的包名**
Stringpkg = mContext.getPackageName();
......
try {
// **③ 将包名、tag、id以及Notification实例一并提交给NotificationManagerService**
service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut,
UserHandle.myUserId());
} catch(RemoteException e) {......}
}
```
NotificationManager会将通知信息发送给NotificationManagerService,并由NotificationManagerService对信息进行进一步处理。注意Notification将通知发送者的包名作为参数传递给了NotificationManagerService。对于一个应用程序来说,tag与id而这一起确定了通知的意图。由于NotificationManagerService作为一个系统服务需要接受来自各个应用程序通知信息,因此对NotificationManagerService来说,确定通知的意图需要在tag与id之外再增加一项:通知发送者的包名。因此由于包名的不一样,来自两个应用程序的具有相同tag与id的通知信息之间不会发生任何冲突。另外将包名作为通知意图的元素之一的原因出于对信息安全考虑。
而将一则通知信息从状态栏中移除则简单得多了,NotificationManager.cancel()方法可以提供这一操作,它接受tag、id作为参数用于指明希望移除的通知所具有的意图。
- 前言
- 推荐序
- 第1章 开发环境部署
- 1.1获取Android源代码
- 1.2Android的编译
- 1.3在IDE中导入Android源代码
- 1.3.1将Android源代码导入Eclipse
- 1.3.2将Android源代码导入SourceInsight
- 1.4调试Android源代码
- 1.4.1使用Eclipse调试Android Java源代码
- 1.4.2使用gdb调试Android C/C 源代码
- 1.5本章小结
- 第2章 深入理解Java Binder和MessageQueue
- 2.1概述
- 2.2Java层中的Binder分析
- 2.2.1Binder架构总览
- 2.2.2初始化Java层Binder框架
- 2.2.3窥一斑,可见全豹乎
- 2.2.4理解AIDL
- 2.2.5Java层Binder架构总结
- 2.3心系两界的MessageQueue
- 2.3.1MessageQueue的创建
- 2.3.2提取消息
- 2.3.3nativePollOnce函数分析
- 2.3.4MessageQueue总结
- 2.4本章小结
- 第3章 深入理解AudioService
- 3.1概述
- 3.2音量管理
- 3.2.1音量键的处理流程
- 3.2.2通用的音量设置函数setStreamVolume()
- 3.2.3静音控制
- 3.2.4音量控制小结
- 3.3音频外设的管理
- 3.3.1 WiredAccessoryObserver 设备状态的监控
- 3.3.2AudioService的外设状态管理
- 3.3.3音频外设管理小结
- 3.4AudioFocus机制的实现
- 3.4.1AudioFocus简单的例子
- 3.4.2AudioFocus实现原理简介
- 3.4.3申请AudioFocus
- 3.4.4释放AudioFocus
- 3.4.5AudioFocus小结
- 3.5AudioService的其他功能
- 3.6本章小结
- 第4章 深入理解WindowManager-Service
- 4.1初识WindowManagerService
- 4.1.1一个从命令行启动的动画窗口
- 4.1.2WMS的构成
- 4.1.3初识WMS的小结
- 4.2WMS的窗口管理结构
- 4.2.1理解WindowToken
- 4.2.2理解WindowState
- 4.2.3理解DisplayContent
- 4.3理解窗口的显示次序
- 4.3.1主序、子序和窗口类型
- 4.3.2通过主序与子序确定窗口的次序
- 4.3.3更新显示次序到Surface
- 4.3.4关于显示次序的小结
- 4.4窗口的布局
- 4.4.1从relayoutWindow()开始
- 4.4.2布局操作的外围代码分析
- 4.4.3初探performLayoutAndPlaceSurfacesLockedInner()
- 4.4.4布局的前期处理
- 4.4.5布局DisplayContent
- 4.4.6布局的阶段
- 4.5WMS的动画系统
- 4.5.1Android动画原理简介
- 4.5.2WMS的动画系统框架
- 4.5.3WindowAnimator分析
- 4.5.4深入理解窗口动画
- 4.5.5交替运行的布局系统与动画系统
- 4.5.6动画系统总结
- 4.6本章小结
- 第5章 深入理解Android输入系统
- 5.1初识Android输入系统
- 5.1.1getevent与sendevent工具
- 5.1.2Android输入系统简介
- 5.1.3IMS的构成
- 5.2原始事件的读取与加工
- 5.2.1基础知识:INotify与Epoll
- 5.2.2 InputReader的总体流程
- 5.2.3 深入理解EventHub
- 5.2.4 深入理解InputReader
- 5.2.5原始事件的读取与加工总结
- 5.3输入事件的派发
- 5.3.1通用事件派发流程
- 5.3.2按键事件的派发
- 5.3.3DispatcherPolicy与InputFilter
- 5.3.4输入事件的派发总结
- 5.4输入事件的发送、接收与反馈
- 5.4.1深入理解InputChannel
- 5.4.2连接InputDispatcher和窗口
- 5.4.3事件的发送
- 5.4.4事件的接收
- 5.4.5事件的反馈与发送循环
- 5.4.6输入事件的发送、接收与反馈总结
- 5.5关于输入系统的其他重要话题
- 5.5.1输入事件ANR的产生
- 5.5.2 焦点窗口的确定
- 5.5.3以软件方式模拟用户操作
- 5.6本章小结
- 第6章 深入理解控件系统
- 6.1 初识Android的控件系统
- 6.1.1 另一种创建窗口的方法
- 6.1.2 控件系统的组成
- 6.2 深入理解WindowManager
- 6.2.1 WindowManager的创建与体系结构
- 6.2.2 通过WindowManagerGlobal添加窗口
- 6.2.3 更新窗口的布局
- 6.2.4 删除窗口
- 6.2.5 WindowManager的总结
- 6.3 深入理解ViewRootImpl
- 6.3.1 ViewRootImpl的创建及其重要的成员
- 6.3.2 控件系统的心跳:performTraversals()
- 6.3.3 ViewRootImpl总结
- 6.4 深入理解控件树的绘制
- 6.4.1 理解Canvas
- 6.4.2 View.invalidate()与脏区域
- 6.4.3 开始绘制
- 6.4.4 软件绘制的原理
- 6.4.5 硬件加速绘制的原理
- 6.4.6 使用绘图缓存
- 6.4.7 控件动画
- 6.4.8 绘制控件树的总结
- 6.5 深入理解输入事件的派发
- 6.5.1 触摸模式
- 6.5.2 控件焦点
- 6.5.3 输入事件派发的综述
- 6.5.4 按键事件的派发
- 6.5.5 触摸事件的派发
- 6.5.6 输入事件派发的总结
- 6.6 Activity与控件系统
- 6.6.1 理解PhoneWindow
- 6.6.2 Activity窗口的创建与显示
- 6.7 本章小结
- 第7章 深入理解SystemUI
- 7.1 初识SystemUI
- 7.1.1 SystemUIService的启动
- 7.1.2 状态栏与导航栏的创建
- 7.1.3 理解IStatusBarService
- 7.1.4 SystemUI的体系结构
- 7.2 深入理解状态栏
- 7.2.1 状态栏窗口的创建与控件树结构
- 7.2.2 通知信息的管理与显示
- 7.2.3 系统状态图标区的管理与显示
- 7.2.4 状态栏总结
- 7.3 深入理解导航栏
- 7.3.1 导航栏的创建
- 7.3.2 虚拟按键的工作原理
- 7.3.3 SearchPanel
- 7.3.4 关于导航栏的其他话题
- 7.3.5 导航栏总结
- 7.4 禁用状态栏与导航栏的功能
- 7.4.1 如何禁用状态栏与导航栏的功能
- 7.4.2 StatusBarManagerService对禁用标记的维护
- 7.4.3 状态栏与导航栏对禁用标记的响应
- 7.5 理解SystemUIVisibility
- 7.5.1 SystemUIVisibility在系统中的漫游过程
- 7.5.2 SystemUIVisibility发挥作用
- 7.5.3 SystemUIVisibility总结
- 7.6 本章小结
- 第8章 深入理解Android壁纸
- 8.1 初识Android壁纸
- 8.2深入理解动态壁纸
- 8.2.1启动动态壁纸的方法
- 8.2.2壁纸服务的启动原理
- 8.2.3 理解UpdateSurface()方法
- 8.2.4 壁纸的销毁
- 8.2.5 理解Engine的回调
- 8.3 深入理解静态壁纸-ImageWallpaper
- 8.3.1 获取用作静态壁纸的位图
- 8.3.2 静态壁纸位图的设置
- 8.3.3 连接静态壁纸的设置与获取-WallpaperObserver
- 8.4 WMS对壁纸窗口的特殊处理
- 8.4.1 壁纸窗口Z序的确定
- 8.4.2 壁纸窗口的可见性
- 8.4.3 壁纸窗口的动画
- 8.4.4 壁纸窗口总结
- 8.5 本章小结