android Notification分析

通常,在手机有未接电话,收到消息或者挂着退出主界面的QQ,在状态栏会有一个Notification,那么,这个notification如何产生的?

通常做法:

Intentintent=newIntent();

intent.setClass(this,Noti.class);

//一般而言,对于需要点击Notification需要迁移到对应的View的需要下面这个操作

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

PendingIntentmPendingIntent=PendingIntent.getActivity(this,0,intent,0);

NotificationmNotification=newNotification();

mNotification.icon=R.drawable.presence_online;//icon的id

mNotification.tickerText="Online";

mNotification.defaults=Notification.DEFAULT_SOUND;

mNotification.flags=Notification.FLAG_AUTO_CANCEL;

mNotification.setLatestEventInfo(this,"QQ","Online",mPendingIntent);

mNotificationManager.notify(0,mNotification);

在android手机中,有一个Notification类,这个类从根本上讲只是一个记录我们需要在状态栏显示Notificationicon的一些信息,比如:要显示的Icon的id,led灯闪烁以及闪烁颜色和闪烁时间,让手机产生振动等。Notification的flag有FLAG_SHOW_LIGHTS,FLAG_AUTO_CANCEL等。有关Notification有三个主要的函数:setLatestEventInfo,notify和cancel

在下面这段代码中,RemoteViews是显示在扩展状态栏上的,也就是将状态栏拉下时显示的Notification,

contentView.setImageViewResource(com.android.internal.R.id.icon,this.icon)则是将我们设定的icon赋给id为com.android.internal.R.id.icon的ImageView,以便在statusBar中调用显示。同样下面都是将本地信息设置为全局信息以便在statusbar中显示。特别要提一下contentIntent是一个PendingIntent,它负责在点击Notification时迁移的View。Notification.java:

publicvoidsetLatestEventInfo(Contextcontext,

CharSequencecontentTitle,CharSequencecontentText,PendingIntentcontentIntent){

RemoteViewscontentView=newRemoteViews(context.getPackageName(),

com.android.internal.R.layout.status_bar_latest_event_content);

if(this.icon!=0){//实际上就是要显示的消息对应的icon

contentView.setImageViewResource(com.android.internal.R.id.icon,this.icon);

}

if(contentTitle!=null){//Notification对应的title

contentView.setTextViewText(com.android.internal.R.id.title,contentTitle);

}

if(contentText!=null){//状态所对应的下标题

contentView.setTextViewText(com.android.internal.R.id.text,contentText);

}

if(this.when!=0){

contentView.setLong(com.android.internal.R.id.time,"setTime",when);

}

this.contentView=contentView;

this.contentIntent=contentIntent;

}

那么它是如何显示到状态栏上的?

NotificationManager调用Notify函数:

publicvoidnotify(Stringtag,intid,Notificationnotification)

{

int[]idOut=newint[1];

INotificationManagerservice=getService();

Stringpkg=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:idcorrupted:sent"+id+",gotback"+idOut[0]);

}

}catch(RemoteExceptione){

}

}

最重要的是,在NotificationManagerService.java中,service.enqueueNotificationWithTag(pkg,tag,id,notification,idOut);它调用NotificationManagerService中方法enqueueNotificationInternal发出声音振动和灯光,这都只要调用相关的系统服务做就可以了。

以何种方式进行通知状态栏显示的?

if(notification.icon!=0){

StatusBarNotificationn=newStatusBarNotification(pkg,id,tag,

r.uid,r.initialPid,notification);

if(old!=null&&old.statusBarKey!=null){

r.statusBarKey=old.statusBarKey;

longidentity=Binder.clearCallingIdentity();

try{

mStatusBar.updateNotification(r.statusBarKey,n);

}

finally{

Binder.restoreCallingIdentity(identity);

}

}else{

longidentity=Binder.clearCallingIdentity();

try{

r.statusBarKey=mStatusBar.addNotification(n);

mAttentionLight.pulse();

}

finally{

Binder.restoreCallingIdentity(identity);

}

}

sendAccessibilityEvent(notification,pkg);

在这里调用了statusbarService.java的updateNotification方法,又调用addNotificationViews将icon显示到状态栏并显示相关信息。

updateNotification这个方法中调用addNotificationViews:

//Constructtheicon.

finalStatusBarIconViewiconView=newStatusBarIconView(this,

notification.pkg+"/0x"+Integer.toHexString(notification.id));

finalStatusBarIconic=newStatusBarIcon(notification.pkg,notification.notification.icon,

notification.notification.iconLevel,notification.notification.number);

if(!iconView.set(ic)){

handleNotificationError(key,notification,"Couldingcreateicon:"+ic);

returnnull;

}

至此,就完成了添加一个icon到Statusbar,同时还有text、title等等。

以DownLoadProvider下载完成后点击下载的Notification,然后消失Notification为例解释FLAG_AUTO_CANCEL原因:

在DownLoadProvider这个app中,DownLoadService会创建一个用于更新下载完成Notification的类DownloadNotification,还有一个开启的线程:updateThread,在这个线程中调用了mNofier.updateNofication(mDownloads.values());然后再DownloadNotification.java中更新下载进度和完成状态,当下载完成时会在StatusBar上显示下载完成这个icon。

那么,系统如何维护状态栏上的Notification呢?也就是如何点击后取消这个Notification呢?

在StatusBarService下privateclassLauncherimplementsView.OnClickListener

是监听点击StatusBarService的函数,当点击这个Notification时,在voidOnClick()方法中有这样的callback:mBarService.onNotificationClick(mPkg,mTag,mId);

mBarService是这样定义的:

IStatusBarServicemBarService=IStatusBarService.Stub.asInterface(

ServiceManager.getService(Context.STATUS_BAR_SERVICE));

这就意味着mBarService使用的是StatusbarManagerService.java中定义的接口,如下:

publicinterfaceNotificationCallbacks{

voidonSetDisabled(intstatus);

voidonClearAll();

voidonNotificationClick(Stringpkg,Stringtag,intid);

voidonPanelRevealed();

voidonNotificationError(Stringpkg,Stringtag,intid,

intuid,intinitialPid,Stringmessage);

}

onNotificationClick是在NotificationManagerService.java中实现的。因此,当点击statusbar上的Notification时就调用NotificationManagerService中的这个响应函数:

publicvoidonNotificationClick(Stringpkg,Stringtag,intid){

cancelNotification(pkg,tag,id,Notification.FLAG_AUTO_CANCEL,

Notification.FLAG_FOREGROUND_SERVICE);

}

cancelNotification定义如下:

privatevoidcancelNotification(Stringpkg,Stringtag,intid,intmustHaveFlags,

intmustNotHaveFlags){

EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL,pkg,id,mustHaveFlags);

synchronized(mNotificationList){

intindex=indexOfNotificationLocked(pkg,tag,id);

if(index>=0){

NotificationRecordr=mNotificationList.get(index);

if((r.notification.flags&mustHaveFlags)!=mustHaveFlags){

return;

}

if((r.notification.flags&mustNotHaveFlags)!=0){

return;

}

mNotificationList.remove(index);

cancelNotificationLocked(r);

updateLightsLocked();

}

}

这就解释了为什么只有设置Notification的flag为Notification.FLAG_AUTO_CANCEL才能取消Notification。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值