Android通知Notification详解

Notification简介

通知是在常规UI界面之外向用户展示消息的工具,当系统发出通知时,它会以图表的形式显示在状态栏中。此时打开通知栏,就可以看到通知的详细信息了。创建通知由Notification.Builder类来控制(API 11添加)。另外,v4的支持库也提供了创建通知的类 NotificationCompat.Builder。在API 11 之前,通知的创建由new Notification()直接创建,现在不建议使用了。

创建Notification

创建通知通过NotificationCompat.Builder,创建完成之后,调用NotificationCompat.Builder.build()方法获取Notification对象,此时通知已经创建好了,下一步发出通知使用NotificationManager.notify()就可以将通知发送出去了。

创建通知的时候可以在Builder中对通知进行设置,包括图标,标题,点击响应等等。有三个基本参数是必须要包含的:

小图标,由 setSmallIcon() 设置
标题,由 setContentTitle() 设置
详细文本,由 setContentText() 设置

下面是一个通知的例子,基本上包含了常用的各项设置:

Notification notification = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_action_new)    //设置小图标,用于状态栏左上角显示
                .setContentTitle("Notification Title")      //设置标题
                .setContentText("Notification content text.")
                .setContentInfo("Content info")
                .setSubText("sub text")
                .setTicker("ticker...")                      //通知到来时状态栏闪过的信息,API21以后不再显示
                .setDefaults(NotificationCompat.DEFAULT_ALL)//设置默认的灯光,提示音和振动,可选值:DEFAULT_ALL,DEFAULT_SOUND,DEFAULT_VIBRATE,DEFAULT_LIGHTS
//                .setLights()
//                .setSound()
//                .setVibrate()
                .setNumber(10)                             //已经被 setSubText取代,显示在时间下方的内容
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)//5.0以后添加
                .setWhen(System.currentTimeMillis())        //设置通知上显示的时间
                .setShowWhen(true)                          //通知是否显示时间
                .setUsesChronometer                         // 设置是否显示时钟表示时间
                .setChronometerCountDown(false);   // 设置时钟是否为倒计时
                .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.largeicon))  //设置大图标
                .setPriority(NotificationCompat.PRIORITY_MAX) //设置等级,可选值有PRIORITY_MIN(-2),PRIORITY_LOW(-1),PRIORITY_DEFAULT(0),PRIORITY_HIGH(1),PRIORITY_MAX(2),默认为0
                .setOngoing(false)                            //设置是否为正在进行的通知。设置为true表示有相关动作正在执行,比如播放音乐。ongoing状态的通知是不会自动消失,也不能手动清除的。除非调用Manager的cancel方法
                .setAutoCancel(true)                          //是否自动消失,true表示响应点击之后自动消失。
                .build();                                     //API16添加,API11使用getNotification()

        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        manager.notify(1, notification);

setVisibility方法有以下可选值:

  • VISIBILITY_PUBLIC 任何情况下都显示通知的完整内容。
  • VISIBILITY_SECRET 不会在锁定屏幕上显示此通知的任何部分。
  • VISIBILITY_PRIVATE 显示通知图标和内容标题等基本信息,但是隐藏通知的完整内容。

设置 VISIBILITY_PRIVATE 后,还可以通过 setPublicVersion() 提供其中隐藏了某些详细信息的替换版本通知内容。

PendingIntent

为通知设定点击事件,需要使用PendingIntent实现。与Intent相比,PendingIntent表示一种特定的处于等待状态,即将发生的一种状态,而Intent则是马上发生的。PendingIntent可以表示三种意图:

  • getActivity(Context context, int requestCode, Intent intent, int flags)
  • getService(Context context, int requestCode, Intent intent, int flags)
  • getBroadcast(Context context, int requestCode, Intent intent, int flags)

requestCode 表示PendingIntent发送方的请求码,它会对PendingIntent的匹配产生影响,当PendingIntent包含的Intent相同,而且requestCode也相同,系统就为认为这是同样的PendingIntent(Extras不影响)。

flags常用的值有四个:

  • FLAG_ONE_SHOT 表示该PendingIntent只能被使用一次,使用完之后就自动cancel。
  • FLAG_NO_CREATE 不会主动创建PendingIntent,如果之前不存在该PendingIntent,get方法返回null,调用失败。
  • FLAG_CANCEL_CURRENT 当前PendingIntent如果已经存在了,那么cancel掉存在的,然后重新创建一个。
  • FLAG_UPDATE_CURRENT 当前PendingIntent如果已经存在了,它们都会被更新,替换成新的Extras。

我们使用notify发送通知的时候,如果id相同,会被认为是同一个通知,更新通知的状态。如果发送一系列id不同,内容相同的通知(包括同样的PendingIntent),这时候点击事件就会根据不同的flag做出不同的判断了。

系统会认为这一系列通知的PendingIntent是同样的,所以如果flag是FLAG_ONE_SHOT,第一个点击的通知会响应事件,剩余的通知在点击的时候就不会有动作了,因为PendingIntent已经被cancel。如果flag是FLAG_CANCEL_CURRENT,那么,每次发送一个通知,系统就会发现PendingIntent已经存在了,于是cancel掉存在的PendingIntent,再生成一个新的,只能给自己用,所以只有最后一个会被响应。如果是FLAG_UPDATE_CURRENT,每发送一条,它都会更新当前存在的所有PendingIntent,并替换为最新的Extras,所以,每个通知都会正常响应。

为通知设置事件,通常情况下这两个参数都设置为0就可以了:

  Intent intent = new Intent(this, SplashActivity.class);
  PendingIntent pi = PendingIntent.getActivity(this, 0 , intent, 0);
  builder.setContentIntent(pi)

设置PendingIntent有三个方法:

  • setContentIntent 点击通知内容
  • setDeleteIntent() 通知被清除时
  • setFullScreenIntent() 全屏事件的Intent,比如在通话时。设置了该项,通知会以浮动的形式闪出

浮动通知是5.0新加的功能,如果通知的优先级设置较高,或者设置了setFullScreenIntent,通知到来的时候手机处于活动状态(点亮屏幕且未锁屏),这是通知会从顶部自动闪出,并且可以响应点击。

事件进阶-TaskStackBuilder

Android中使用任务栈来管理Activity,这个应该都很清楚了,现在考虑这么一种情况:通过点击通知栏打开一个Activity,这时候,通过Back返回,就会销毁当前Activity,直接返回桌面了,如果我们想返回该应用的首页,而不是退出,就要用到TaskStackBuilder。

我们先看一下TaskStackBuilder的使用方法:

        Intent intent = new Intent(this, SplashActivity.class);// 构建一个指向SplashActivity.class的Intent
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);//获取TaskStackBuilder 
        stackBuilder.addParentStack(SplashActivity.class)
        stackBuilder.addNextIntent(intent);
        PendingIntent pi2 = stackBuilder.getPendingIntent(0,0);

首先通过TaskStackBuilder.create(this)创建一个任务栈,下一步方法是addParentStack,这个方法比较奇葩,我们这里指定的是SplashActivity.class,实际上它添加的并不是SplashActivity。它需要与Manifest中的对应Activity的parentActivityName属性结合使用。

<activity
            android:name=".SplashActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:parentActivityName=".DrawableActivity"
            >

SplashActivity指定了它的父Activity为DrawableActivity,所以我们调用addParentStack(SplashActivity.class)之后,此时返回栈中只是添加了DrawableActivity

addNextIntent用来继续向返回栈添加Activity,这里才将SplashActivity添加进来。当然我们也可以继续创建指向其他Activity的Intent,使用addNextIntent向返回栈中添加新的Activity,最后添加的Activity处于最顶层,依次向下。(实际上addParentStack并不是必须的,系统使用addNextIntent添加Activity进栈时,仍然会读取它的android:parentActivityName并添加对应的父Activity。另外,请不要对被设为parentActivity的Activity再设置android:parentActivityName,会导致ANR)

使用TaskStackBuilder之后,不能根据intent来创建PendingIntent了,需要使用getPendingIntent方法,获取到之后设置给Notification,这样就实现了指定返回Activity的功能。

为Activity指定任务栈

上面介绍了创建任务栈并管理其中的Activity,从而实现返回指定Activity的功能。但是,有时候我们需要的功能很简单,点击通知打开Activity,按下Back键返回桌面。此时,如果Activity所在的应用处于开启状态,新开启的Activity会直接添加到当前应用的栈中,所以按下Back之后返回的是应用而不是桌面。

要实现这种功能很简单,为新建的Activity创建新的任务栈就可以了。

首先设置要启动的Activity属性:

<activity>
......
    android:taskAffinity=""  //指定任务栈的Affinity,与Intent的NEW_TASK相结合,在新的任务栈启动
    android:excludeFromRecents="true">//不显示在最近任务列表
</activity>

然后:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 再设置PendingIntent给通知就可以了。FLAG_ACTIVITY_CLEAR_TASK表示清空要启动的Activity所处的任务栈,确保android:taskAffinity指定的值唯一的情况下可以不设置。

其他常用设置

  • 进度条通知
    使用setProgress(max, progress, false)来设置及进度条通知,并更新进度。第三个参数设置为true表示循环滚动不显示准确进度的进度条。注意进度条与subContent不能同时设置,否则进度条不能显示。

  • 设置样式setStyle()

    系统已经提供了几个样式给我们使用,有BigPictureStyleBigTextStyleMessagingStyleInboxStyle等。

自定义外观

我们可以通过RemoteView来对通知栏进行自定义View的设置。有四个相关方法

setContent 设置普通视图,高度限制为 64 dp
setCustomContentView设置普通视图,高度限制为 64 dp
setCustomBigContentView() 设置扩展视图,高度可以扩展到256dp
setCustomHeadsUpContentView() 设置浮动通知视图

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容