好久没写东西,我得承认,是自己懒了。
解过几个statusbar的bug,觉得notification还是挺有意思的,分析一下流程,以作备忘吧。
- 通知的接收
1. notification由系统或第三方应用封装发出notificationManager.notify()。
2. 通知进入一个队列NotificationManagerService.enqueueNotificationInternal()。
3. 在上面方法里面会发现一个熟悉的身影,就是mStatusBar,它是StatusBarManagerService的化身。调用mBar.addNotification(key,notification);
4. 通过linux查找命令先定位IStatusBar.aidl的位置,然后在该最外路径下搜索IStatusBar.Stub可以找到具体实现它的java文件,这里我们找到了CommandQueue,java。然后调用CommandQueue. addNotification(),该方法利用handle发出一个消息:MSG_ADD_NOTIFICATION,跳转到回调函数addNotification(ne.key,ne.notification); PhoneStatusBar实现了这个回调方法。
5. 以上一个通知算是被系统statusBar所接收到。
- 通知的statusbar显示
public void addNotification(IBinder key, StatusBarNotification notification) { // 1.初始化一个状态栏图标来体现该notification StatusBarIconView iconView = addNotificationViews(key, notification); if (iconView == null) return; } if (immersive) { //无实际作用,4.1会被注释 } else if (notification.notification.fullScreenIntent != null) { // 2.not immersive & a full-screen alert should be shown,比如电话和闹钟的通知灰常nb Slog.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent"); try { notification.notification.fullScreenIntent.send(); } catch (PendingIntent.CanceledException e) { } } else { // 3.usual case: status bar visible & not immersive。普通notification都走这道,用一个动画的形式显示该通知的文字信息。 tick(notification); } // 4.Recalculate the position of the sliding windows and the titles. setAreThereNotifications(); // 5.刷新一下ExpandedView的位置, updateExpandedViewPos(EXPANDED_LEAVE_ALONE); }
- 通知的expendView显示
代码都在上一步走完了。
条目的添加是addNotificationViews():
// 1.Construct the expanded view. NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);
view的刷新是addNotification():
// 5.刷新一下ExpandedView的位置, updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
- 通知的更新
同样是从CommandQueue. updateNotification()开始走,然后到PhoneStatusBar. updateNotification()。代码流程和通知的添加几乎一致,只是没有add view这一步。
- 通知的发送
protected void sendNotification() { // TODO Auto-generated method stub Log.e(TAG, "-----sendNotifications----"); // 1.实例化intent和获取通知的服务。 Intent mIntent = new Intent(); NotificationManager notificationManager = (NotificationManager) mContext .getSystemService(Context.NOTIFICATION_SERVICE); mIntent.setClass(mContext, ShowHello.class); PendingIntent mPendingIntent = PendingIntent.getActivity(mContext, 0, mIntent, 0); // 2.设置通知的相应属性 // mNotification.fullScreenIntent = mPendingIntent;//这句话的作用是决定通知是否自动弹出那个可跳转的activity。 mNotification.defaults |= Notification.DEFAULT_SOUND;//设置通知是否播放声音。 mNotification.flags = Notification.FLAG_ONGOING_EVENT; // 在4.0的expendview里多显示一张图片,2.3系统会报错 mNotification.largeIcon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_action_search); // 显示通知调用下面的方法是必须的,但在api11会被deprecated,使用Notification.Builder代替。 mNotification.setLatestEventInfo(mContext, tick, TAG, mPendingIntent); // 3.唤醒通知 notificationManager.notify(R.drawable.ic_launcher, mNotification); }
- 各个主要版本的变化
分析时是以4.0为准,为了兼顾其他也顺便看了一遍2.3,4.1的流程,notification总的来说没有大的变化,API升级后有些方法被弃用有了新的实现,与之相关的就是状态栏为了适配pad和更高分辨率机型进行了一些重构,体现在我们这里就是2.3的statusBarService在4.0后改名为phoneStatueBar。4.0加入的immersive模式在4.1被彻底废除。
- 三言两语
Notification的前世来生也就这样,生平中有过纠结的是NotificationManager,NotificationManagerService,StatusBarManagerService,phoneStatueBar,CommandQueue。