天天看點

SystemUI中顯示通知流程1.參考:2.NotificationListenerService:3.時序圖:4.時序圖解讀:

目錄

1.參考:

2.NotificationListenerService:

3.時序圖:

4.時序圖解讀:

1.參考:

通知framework中的執行流程請參考:

https://blog.csdn.net/zhao5214319/article/details/98848708

2.NotificationListenerService:

在SystemUI中會注冊這個Service用來接收從Framework中傳過來的通信資訊,也就是StatusBarNotification這個類。這個過程使用的是Binder通信機制,AIDL接口為INotificationListener,在Framework代碼中實作了這個接口,但這個實作是一個抽象服務類(extends Service)的,本質上是一個Services,但在SystemUI中的使用上可以了解就是向NotifcationManageService中注冊的一個回調,當需要發送一個通知時,Framewok中接收到通知資訊進行記錄并處理,處理完了之後調用回調将資訊傳到SystemUI進行處理。

  • 注冊流程:

要了解NotificationListenerService的注冊流程首先要連接配接SystemUI的啟動流程,在這個裡做一個簡單的介紹。

啟動流程大約分為幾個階段:

1>java環境啟動階段(fastboot->Kernel->java虛拟機)

2>framework服務啟動階段(參考:https://blog.csdn.net/zhao5214319/article/details/96483297)

3>SystemUI啟動階段

主要簡單的介紹下SystemUI階段,因為NotificationListenerService注冊就是在這個階段進行的,SystemUI啟動流程會另起一篇文章詳細學習。

時序圖如下:

SystemUI中顯示通知流程1.參考:2.NotificationListenerService:3.時序圖:4.時序圖解讀:

重點解讀:

1>SystemUIApplicaton建立SystemBar對象時會使用工廠模式,若工廠中存在則直接使用,若不存則通過反射的newInstance方法建立此對象,并将對象加入工廠中。這塊時序圖中不能清晰表達,是以在這重點介紹

2>在SystemBar建立PhoneStatusBar對象時會讀取配置檔案,根據配置檔案中配置的包名+類名進行建立,是以這塊廠家可以配置自己的statusBar的java類,在進行此項開發時最好繼承PhoneStatusBar這個類,當然繼承BaseStatusBar或其父類也可以,但這樣就需要自己實作大量的功能,會消耗大量的資源。

3>congfig.xml的配置如下:

<string name="config_statusBarComponent"
translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string>
           

4>時序圖中調用了大量的start()方法,請注意:SystemBar、PhoneStatusBar和BaseStatusBar既不是服務,也不是建立立的線程,start就是一個java的最普通的方法。

5>在NotificationManagerService中NotificationListenerService一般有4個。

3.時序圖:

SystemUI中顯示通知流程1.參考:2.NotificationListenerService:3.時序圖:4.時序圖解讀:

4.時序圖解讀:

通知是怎麼傳到NotificationListenerService中的請參考此篇文章:

https://blog.csdn.net/zhao5214319/article/details/98848708

在NotificationListenerService的onNotificationPosted方法中首先就是新開一個線程,這樣做有以下幾點好處:

  1. 将framework中的線程釋放掉,這樣可以節省Framwork程序的記憶體空間,防止因記憶體不夠導緻的問題
  2. 釋放Binder通道,防止資源暫用導緻使用通道堵塞,進而引起的crash問題
  3. 由于新開的線程是運作在SystemUI程序中的,出問題後可以通過程序ID快速定位那個子產品出的問題

新開線程處理的好處多多,簡單列舉幾條,希望以後在使用Binder通信時,把這個當成一個準則來使用(Binder接口不需要傳回值時,要開線程來處理所有的活動,無論是耗時還是非耗時)

線程啟動後首先就是對RemoteImput的處理,這是通知的一種新功能,支援使用者的輸入操作,增加了通知于使用者的可互動性,最常用的就是短信子產品,可以通過此工具快速回複短消息,此功能會單獨記錄,在這就不在啰嗦。

在RemoteInput之後就需要判斷此次通知消息發過了是要進行更新處理還是要進行增加處理了:在此之前要了解NotificationData的作用。NotificationData是一個記錄所有SystemUI中通知資訊的實體類,它存在一個内部靜态類Entry,這個Entry存放一條通知在SystemUI中顯示所有需要的所有資訊(包含RemoteViews),而NotificationData中有一個成員變量mEntries,它是一個ArrayMap類型的變量,通過Key-Value方式将所有通知對應的Entry,也是就是說,你在通知欄中看到的每一條通知都會有其對應的一個Entry。新增一條通知時,SystemUI會将StatusBarNotification對象,按照一定的規則轉成一條Entry存儲在SystemUI中,并将StatusBarNotification的對象釋放。

這個Key值很重要,判斷是否是新增就需要判斷這個Key值能否從NotificationData中拿到有效資料,若不存在,則新增;若存在就更新。是以就要保證這個Key值是唯一的,可以通過Framework的StatusbarNotification中的key()方法來讀懂這個Key值是怎麼保證唯一的:

private String key() {
    String sbnKey = user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid;
    if (overrideGroupKey != null && getNotification().isGroupSummary()) {
        sbnKey = sbnKey + "|" + overrideGroupKey;
    }
    return sbnKey;
}
           

一般情況下發通知是不設定NotificationGroup的,系統會自動配置設定一個Default Group,是以上面的If語句就可以忽略不看了,主要看方法的第一句指派語句。可以發現:這個Key與5個變量值有關:

1、userID               多使用者使用,一般手機都是機主使用者在使用,是以這個值始終為0

2、packageName  應用程式包名,系統通知都是”android“,在Andorid這個值可以區分不同的應用程式的

3、ID                      通知ID值,這個在發送通知時要求是應用程式中唯一的

4、TAG                   這個值使用者發送通知時可以使用三參事的notifity方法自由設定的,但一般使用雙參數的notify發通知時這個值預設為null

5、UID                   Linux配置設定給應用程式的唯一ID值,不同的應用程式UID是不同的,有些類似于PackageName

是以應用程式可以通過第2、3、4條保證這個Key值是唯一的,系統程式就需要在加上第5條了。

判斷出來了重新整理還是新增,就需要根據這個狀态來執行相應的流程了。在這需要指出,這2個流程之間的關系是包含關系,也就是說新增流程包含重新整理流程,但具體細節上又有一些差别,是以時序圖上詳細的畫出了新增流程,重新整理流程隻畫一少部分。

在addNotification方法中會建立通知對應的Entry、StatusBarIconView(狀态欄上顯示的小圖示)、建立5個RemoteViews并對所有的View進行初始化,建立一個ExpandableNotificationRow,并将這5個RemoteViews存儲到ExpandableNotificationRow中等待顯示到界面上。最後還要加上點選事件的注冊(點選此通知後,通知消失,打開對應注冊的Activity)

建立完成Entry,并初始化完成後,就要調用addNotificationViews方法将Entry存儲到NotificationData中,此時資料和UI上顯示的就不一緻了,就需要調用updateNotifications方法保持NotificationData中的資料和UI上顯示的一緻。

在重新整理每一條通知資料時,首先要對資料進行排序,之後将新的通知ExpandableNotificationRow加入到NotificationStackScrollLayout上進行顯示,這個過程會進行排序添加,添加完成後調用updateRowStates更新狀态,最後就顯示了通知下拉狀态中了。

重新整理過程要比添加流程簡單一些,先在NotificationData中取到Entry,并将Entry中的ExpandableNotificationRow存儲的5個RemoteViews進行更新,最後在重新整理就完成了。

歡迎大家斧正