通知信息是狀態欄中最常用的功能之一。根據用戶是否拉下下拉卷簾,通知信息表現為一個位于狀態欄的圖標,或在下拉卷簾中的一個條目。另外,通知信息還可以在其添加入狀態欄之時發出聲音,以提醒用戶注意查看。通知信息即可以表示一條事件,如新的短消息到來、出現了一條未接來電等,也可以用來表示一個正在后臺持續進行著的工作,如正在下載某一文件、正在播放音樂等。
#### 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 本章小結