深入理解Notification機制


Android藍牙控制遙控器的源碼
http://www.eoeandroid.com/thread-195605-1-1.html

基於Android 砸蛋的游戲
http://www.eoeandroid.com/thread-195603-1-1.html

Android下瀏覽其文件系統的工具
http://www.eoeandroid.com/thread-195591-1-1.html

 

先貼上這些源碼里面相關的文件:

     framework/base/core/java/android/app/NotificationManager.java

       framework/base/services/java/com/android/server/NotificationManagerService.java{@hide} extends INotificationManager.Stub

       framework/base/services/java/com/android/server/StatusBarManagerService.java  extends IStatusBarService.Stub

 

       framework/base/core/java/com/android/internal/statusbar/StatusBarNotification  implements Parcelable

       framework/base/core/java/com/android/internal/statusbar/IStatusBar.aidl

        framework/base/core/java/com/android/internal/statusbar/IStatusBarService.aidl

       framework/base/core/java/com/android/internal/statusbar/StatusBarNotification.aidl   

 

       framework/base/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java extends Service implements CommandQueue.Callbacks

       framework/base/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java extends IStatusBar.Stub

1>.系統啟動的時候:framework/base/services/java/com/android/server/SystemServer.java中:

try {   
        Slog.i(TAG, "Status Bar");     
        statusBar = new StatusBarManagerService(context);   
        ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);   
} catch (Throwable e) {   
         Slog.e(TAG, "Failure starting StatusBarManagerService", e);   
}   
            
try {   
        Slog.i(TAG, "Notification Manager");   
         notification = new NotificationManagerService(context, statusBar, lights);   
                          
         ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);   
} catch (Throwable e) {   
         Slog.e(TAG, "Failure starting Notification Manager", e);   
}  

這段代碼是注冊狀態欄管理和通知管理這兩個服務。

2>.在StatusBarManagerService.java中,有addNotification,removeNotification,updateNotification等方法用於管理傳遞給他的通知對象。這個類是一些管理方法,實際執行相關動作的是在IStatusBar.java里面,這個是framework/base/core/java/com/android/internal/statusbar/IStatusBar.aidl自動生成的用於IPC的類。

 

拿addNotification方法示范:

public IBinder addNotification(StatusBarNotification notification) {   
                synchronized (mNotifications) {   
                IBinder key = new Binder();   
                mNotifications.put(key, notification);   
                if (mBar != null) {   
                try {   
                    mBar.addNotification(key, notification);   
                  } catch (RemoteException ex) {   
               }   
            }   
            return key;   
        }   
      }  

這里的mBar其實就是IStatusBar的實例

volatile IStatusBar mBar;  

為了防止NPE,每次使用mBar都先判斷是否為null,mBar是在方法registerStatusBar中傳遞進來的。

public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,   
            List<IBinder> notificationKeys, List<StatusBarNotification> notifications) {   
        enforceStatusBarService();   
    
        Slog.i(TAG, "registerStatusBar bar=" + bar);   
        mBar = bar;   
        synchronized (mIcons) {   
            iconList.copyFrom(mIcons);   
        }   
        synchronized (mNotifications) {   
            for (Map.Entry<IBinder,StatusBarNotification> e: mNotifications.entrySet()) {   
                notificationKeys.add(e.getKey());   
                notifications.add(e.getValue());   
            }   
        }   
        }  
framework/base/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java實現IStatusBar.java接口,
framework/base/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java提供IStatusBar相關服務。
 
CommandQueue.java中,IStatusBar.java里面對應的方法是用callback的形式調用的,callback的實現當然就在對應的服務提供類也就是StatusBarService.java中提供的啦。
CommandQueue.java中:
public void addNotification(IBinder key, StatusBarNotification notification) {   
        synchronized (mList) {   
            NotificationQueueEntry ne = new NotificationQueueEntry();   
            ne.key = key;   
            ne.notification = notification;   
            mHandler.obtainMessage(MSG_ADD_NOTIFICATION, 0, 0, ne).sendToTarget();   
                //這句話對應的mHandler執行語句是:   
                //  final NotificationQueueEntry ne = (NotificationQueueEntry)msg.obj;   
            // mCallbacks.addNotification(ne.key, ne.notification);   
                //也就是調用回調函數里面的addNotification。   
        }   
    }     

在StatusBarService.java中:

mCommandQueue = new CommandQueue(this, iconList);//StatusBarService實現了CommandQueue中的CommandQueue.Callbacks接口   
        mBarService = IStatusBarService.Stub.asInterface(   
                ServiceManager.getService(Context.STATUS_BAR_SERVICE));   
        try {   
                //將IStatusBar實現類的對象傳遞到StatusBarManagerService.java中,這里的mCommandQueue就是上面對應的mBar啦。   
            mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications);   
        } catch (RemoteException ex) {   
            // If the system process isn't there we're doomed anyway.   
        }  

最終執行狀態欄更新通知等事件都是在實現的CommandQueue.Callbacks里面執行。還是以addNotification為例:

public void addNotification(IBinder key, StatusBarNotification notification) {   
        boolean shouldTick = true;   
        if (notification.notification.fullScreenIntent != null) {   
            shouldTick = false;   
            Slog.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");   
            try {   
                notification.notification.fullScreenIntent.send();   
            } catch (PendingIntent.CanceledException e) {   
            }   
        }    
    
        StatusBarIconView iconView = addNotificationViews(key, notification);   
        if (iconView == null) return;   
          //。。。以下省略N字。  

大致流程就是:調用StatusBarManagerService.java中的addNotification方法->(mBar不為空的話)執行mBar.addNotification(key, notification);->對應的是CommandQueue中的addNotification(IBinder key, StatusBarNotification notification)->CommandQueue中的mCallbacks.addNotification(ne.key, ne.notification);->StatusBarService中的addNotification。

3>.上面是提供相關功能的一些類,具體的notification的管理類是framework/base/services/java/com/android/server/NotificationManagerService.java,從該類的定義public class NotificationManagerService extends INotificationManager.Stub可以知道

他是用來實現接口中INotificationManager中定義的相關方法並向外部提供服務的類。主要向外提供public void enqueueNotificationWithTag(String pkg, String tag, int id, Notification notification,int[] idOut)方法。該方法實際上是調用public void enqueueNotificationInternal(String pkg, int callingUid, int callingPid,String tag, int id, Notification notification, int[] idOut),他里面提供了notification的具體處理方法。

 摘取部分代碼片段看看:

if (notification.icon != 0) {   
                StatusBarNotification n = new StatusBarNotification(pkg, id, tag,   
                        r.uid, r.initialPid, notification);   
                if (old != null && old.statusBarKey != null) {   
                    r.statusBarKey = old.statusBarKey;   
                    long identity = Binder.clearCallingIdentity();   
                    try {   
                        mStatusBar.updateNotification(r.statusBarKey, n);   
                    }   
                    finally {   
                        Binder.restoreCallingIdentity(identity);   
                    }   
                } else {   
                    //省略。。。  

當判斷好需要更新通知的時候調用mStatusBar.updateNotification(r.statusBarKey, n);方法,這個就是StatusBarManagerService.java中的addNotification方法,這樣就進入上面所說的處理流程了。

4>. 在3中的NotificationManagerService.java是管理notification的服務,服務嘛就是用來調用的,調用他的就是大家熟悉的NotificationManager了。

在NotificationManager.java中,有一個隱藏方法,用來得到INotificationManager接口對應的服務提供類,也就是NotificationManagerService了。

/** @hide */  
    static public INotificationManager getService()   
    {   
        if (sService != null) {   
            return sService;   
        }   
        IBinder b = ServiceManager.getService("notification");   
        sService = INotificationManager.Stub.asInterface(b);   
        return sService;   
    }  

再看看更熟悉的notify方法,其實是執行:

public void notify(String tag, int id, Notification notification)   
    {   
        int[] idOut = new int[1];   
        INotificationManager service = getService();   
        String pkg = mContext.getPackageName();   
        if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");   
        try {   
            service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut);   
            if (id != idOut[0]) {   
                Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);   
            }   
        } catch (RemoteException e) {   
        }   
    }  

ervice.enqueueNotificationWithTag(pkg, tag, id, notification, idOut);也就是3中提到的那個對外公開的服務方法了,這樣就進入了上面提到的處理流程了。

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM