第十九章 Android中的通知Notification

通知(Notification)这个功能对于我们来说非常的常见。打开手机的时候,各种软件的推送消息蜂拥而至,然后我们的通知栏被挤得满满的。你看到的消息提示框就是通知。

1. Notification 状态栏通知的作用

从JellyBean 以来,通知系统做了一次被引入Android 以来最重大的结构性和功能性的变动。

  • 通知可以包含操作,用户可以在通知抽屉中直接做出回应
  • 通知在大小和布局方面更加灵活,可以展开显示更多的信息
  • 通知有了优先级高低的排列方式,而不仅仅是时间的排列

1.1 通知状态栏的作用

1.显示接收短消息以及即时信息等(短信 ,QQ,微信等)
2.显示客户端的推送消息 (广告,推荐消息等)
3.显示正在进行的事务 (播放器的显示,版本更新等)

2. Notification的基本用法

通知的基本用法还是很灵活的,可以在活动中创建,也可以在广播接收器中创建,还可以在服务中创建。一般在广播和服务中用的比较多,因为只有在程序进入后台的时候,我们才需要使用通知,活动中使用的比较少。

2.1 通知的基本布局

通知的基本布局包括:

  • 发送通知的应用图标或者发送人的头像
  • 通知标题和消息
  • 时间戳
  • 当主图标显示发送人头像时,在副图标位置显示应用图标
通知的基本布局

2.2 通知的扩展布局

通知的扩展布局显示消息的前面几行或者图片的预览,后面的信息折叠起来,这样用户就可以看到更多的信息。用户可以通过 pinch-zoom 或者双手指滑动来打开扩展布局。Android 为单条消息提供了两种扩展布局 (文字和图像) 供你开发应用时使用。

通知的扩展布局

从 Jelly Bean 开始,Android 支持在通知底部显示附加操作。通过这些操作,用户可以对通知直接执行常见的任务,而不用打开应用。这样可以加快操作,配合上滑出消失操作,使用户的通知抽屉体验更加顺滑。
可以放入通知中的操作有以下特点:

  • 对于该通知重要、常用和典型的操作
  • 时间紧迫的
  • 不会与相邻的操作重复的

不要放置:

  • 模糊的
  • 和点击通知得到的效果一样的操作,例如阅读或者打开

2.3 通知的优先级

从 Jelly Bean 开始,Android 为通知增加了优先级标志。这样你可以使重要的通知相对于其他通知,总是显示在第一个。请通过以下的表格仔细选择通知的优先级

优先级 用户
MAX 重要而紧急的通知,通知用户这个事件是时间上紧迫的或者需要立即处理
HIGH 高优先级用于重要的通信内容,例如短消息或者聊天,这些都是对用户来说比较有兴趣的。
DEFAULT 默认优先级用于没有特殊优先级分类的通知。
LOW 低优先级可以通知用户但又不是很紧急的事件。
MIN 用于后台消息 (例如天气或者位置信息)。最低优先级通知将只在状态栏显示图标,只有用户下拉通知抽屉才能看到内容。
通知的优先级

2.4 创建通知的步骤

  1. 创建一个通知管理类NotificationManager,通过调用 getSystemService()的方法获得。getSystemService方法接收一个字符串参数用于确定获取系统的哪个服务,传入Context.NOTIFICATION_SERVICE
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
  1. 使用Builder构造器创建Notification对象。这里使用 support-v4库中提供的NotificationCompat
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context);  
或者这样写:
Notification notification = NotificationCompat.Builder(context).builder();  
  1. 对Builder进行配置(写法和dialog差不多)
    mBuilder.setContentTitle("测试标题")//设置通知栏标题  
    .setContentText("测试内容") //设置通知栏显示内容
    .setContentIntent(getDefalutIntent(Notification.FLAG_AUTO_CANCEL)) //设置通知栏点击意图  
//  .setNumber(number) //设置通知集合的数量  
    .setTicker("测试通知来啦") //通知首次出现在通知栏,带上升动画效果的  
    .setWhen(System.currentTimeMillis())//通知产生的时间,会在通知信息里显示,一般是系统获取到的时间  
    .setPriority(Notification.PRIORITY_DEFAULT) //设置该通知优先级  
//  .setAutoCancel(true)//设置这个标志当用户单击面板就可以让通知将自动取消    
    .setOngoing(false)//ture,设置他为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载,同步操作,主动网络连接)  
    .setDefaults(Notification.DEFAULT_VIBRATE)//向通知添加声音、闪灯和振动效果的最简单、最一致的方式是使用当前的用户默认设置,使用defaults属性,可以组合  
    //Notification.DEFAULT_ALL  Notification.DEFAULT_SOUND 添加声音 // requires VIBRATE permission  
    .setSmallIcon(R.drawable.ic_launcher);//设置通知小ICON  
 
  1. 设置通知栏PendingIntent(点击动作事件等都包含在这里)。PendingIntent 从名字上看和Intent 很像,它们都指明一个意图,都可以开启活动,开启服务和发送广播。但是Intent 倾向于立即执行某个动作,而PendingIntent 倾向于某个时机执行动作。

  2. 最后一步,发送通知请求

mNotificationManager.notify(notifyId, mBuilder.build());  

notify()方法有两个参数,一个参数是id,要保证每个通知所指定的id都是不同的,第二个参数则是Notification对象。
显示一个通知:

mNotificationManager.notify(1, mBuilder.build());  

2.5 通知的方法

1. 设置提醒的标志符号flags,添加声音,设置闪灯,震动等效果。
两种设置方法:
1). 实例化之后,在设置flags

Notification notification = mBuilder.build();  
notification.flags = Notification.FLAG_AUTO_CANCEL;  

2). 通过setContentIntent(PendingIntent intent)方法中的意图设置对应的flags

public PendingIntent getDefalutIntent(int flags){  
    PendingIntent pendingIntent= PendingIntent.getActivity(this, 1, new Intent(), flags);  
    return pendingIntent;  
} 

提醒标志符成员:
Notification.FLAG_SHOW_LIGHTS //三色灯提醒,在使用三色灯提醒时候必须加该标志符
Notification.FLAG_ONGOING_EVENT //发起正在运行事件(活动中)
Notification.FLAG_INSISTENT //让声音、振动无限循环,直到用户响应 (取消或者打开)
Notification.FLAG_ONLY_ALERT_ONCE //发起Notification后,铃声和震动均只执行一次
Notification.FLAG_AUTO_CANCEL //用户单击通知后自动消失
Notification.FLAG_NO_CLEAR //只有全部清除时,Notification才会清除 ,不清楚该通知(QQ的通知无法清除,就是用的这个)
Notification.FLAG_FOREGROUND_SERVICE //表示正在运行的服务

2. setDefaults(int defaults) (NotificationCompat.Builder中的方法,用于提示)
功能:向通知添加声音、闪灯和振动效果的最简单、使用默认(defaults)属性,可以组合多个属性(和方法1中提示效果一样的)
对应属性:
Notification.DEFAULT_VIBRATE //添加默认震动提醒 需要 VIBRATE permission
Notification.DEFAULT_SOUND // 添加默认声音提醒
Notification.DEFAULT_LIGHTS// 添加默认三色灯提醒
Notification.DEFAULT_ALL// 添加默认以上3种全部提醒
3. setVibrate(long[] pattern)
功能:设置震动方式

.setVibrate(new long[] {0,300,500,700});  

实现效果:延迟0ms,然后振动300ms,在延迟500ms,接着在振动700ms。
写法二:

mBuilder.build().vibrate = new long[] {0,300,500,700};  

4. setLights(intledARGB ,intledOnMS ,intledOffMS )
功能:android支持三色灯提醒,这个方法就是设置不同场景下的不同颜色的灯。
描述:其中ledARGB 表示灯光颜色、 ledOnMS 亮持续时间、ledOffMS 暗的时间。
注意:1)只有在设置了标志符Flags为Notification.FLAG_SHOW_LIGHTS的时候,才支持三色灯提醒。
2)这边的颜色跟设备有关,不是所有的颜色都可以,要看具体设备。

.setLights(0xff0000ff, 300, 0)  

同理,实现同样的效果:

Notification notify = mBuilder.build();  
notify.flags = Notification.FLAG_SHOW_LIGHTS;  
notify.ledARGB = 0xff0000ff;  
notify.ledOnMS = 300;  
notify.ledOffMS = 300;  

如果希望使用默认的三色灯提醒,设置了方法(2)中默认为DEFAULT_LIGHTS即可。
5. setSound(Uri sound)
功能:设置默认或则自定义的铃声,来提醒。

//获取默认铃声  
.setDefaults(Notification.DEFAULT_SOUND)  
//获取自定义铃声  
.setSound(Uri.fromFile(new File("file:///sdcard/xx/xx.mp3")))  
//获取Android多媒体库内的铃声  
.setSound(Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "5"))  

6. setPriority(int pri)
对应属性(作用看上图就可知道):
Notification.PRIORITY_DEFAULT
Notification.PRIORITY_HIGH
Notification.PRIORITY_LOW
Notification.PRIORITY_MAX
Notification.PRIORITY_MIN
7. setOngoing(boolean ongoing)
功能:设置为ture,表示它为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载,同步操作,主动网络连接)
8. setProgress(int max, int progress,boolean indeterminate)
属性:max:进度条最大数值 、progress:当前进度、indeterminate:表示进度是否不确定,true为不确定,如下第3幅图所示 ,false为确定下第1幅图所示
功能:设置带进度条的通知,可以在下载中使用

带进度条的通知

9. 设置点击取消
点击通知消息之后,上面的图标还是没有消掉
1)在buider配置的方法中添加

.setAutoCancel(true)

2 ) 在创建管理通知类NotificationManager的时候,调用cancel()方法

NotificationManager manager= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
manager.cancel(1);

这里的这个1 ,是在创建通知的时候给每条通知指定的notifyId 。因此如果你想取消哪条id就传哪个值。

2.6 PendingIntent 的用法

PendingIntent的用法很简单。它主要提供了几个静态方法用于获取PendingIntent的实现,可以根据需求使用getActivity()方法,getBroadcast()方法,getService()方法,这几个方法里面的参数都是一样的。第一个参数是Context ,第二个参数一般用不到传个0就好,第三个参数是一个Intent的对象,通过它来构建PendingIntent的“意图”,第四个用于确定PendingIntent的行为.
2.6.1 PendingIntent的位标识符:
FLAG_ONE_SHOT 表示返回的PendingIntent仅能执行一次,执行完后自动取消
FLAG_NO_CREATE 表示如果描述的PendingIntent不存在,并不创建相应的PendingIntent,而是返回NULL
FLAG_CANCEL_CURRENT 表示相应的PendingIntent已经存在,则取消前者,然后创建新的PendingIntent,这个有利于数据保持为最新的,可以用于即时通信的通信场景
FLAG_UPDATE_CURRENT 表示更新的PendingIntent

2.6.2 在各种情况下情况下它还会根据各种情况触发效果:
contentIntent:在通知窗口区域,Notification被单击时的响应事件由该intent触发;
deleteIntent:当用户点击全部清除按钮时,响应该清除事件的Intent;
fullScreenIntent:响应紧急状态的全屏事件(例如来电事件),也就是说通知来的时候,跳过在通知区域点击通知这一步,直接执行fullScreenIntent代表的事件。
1). 点击通知栏跳转到指定的XXActivity中

Intent intent = new Intent(context,XXX.class);  
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);  
mBuilder.setContentIntent(pendingIntent)

2). 在执行了清空全部的通知操作时候,可以设置以下方法来相应这个事件

Intent deleteIntent = new Intent();  
deleteIntent.setClass(context, XXXReceiver.class);  
deleteIntent.setAction(DELETE_ACTION);  
notification.deleteIntent = PendingIntent.getBroadcast(context, 0, deleteIntent, 0);  

3). 在响应紧急事件(如来电)时候,可以设置以下方法来相应这个事件

setFullScreenIntent(PendingIntent intent, boolean highPriority)

3. 创建自定义的通知栏

Notification的自定义布局是RemoteViews,和其他RemoteViews一样,在自定义视图布局文件中,仅支持FrameLayout、LinearLayout、RelativeLayout三种布局控件和AnalogClock、Chronometer、Button、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView和AdapterViewFlipper这些显示控件,不支持这些类的子类或Android提供的其他控件。否则会引起ClassNotFoundException异常

3.1 创建自定义的步骤

1). 创建自定义的视图
2). 获取远程视图对象
3). 设置PendingIntent(来响应各种事件)
4). 发起Notification

1.创建自定义的视图

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="100dp">
<ImageView
    android:id="@+id/iv_not_head_image"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="match_parent"
    android:src="@mipmap/youname"
    android:scaleType="centerCrop"
    />
    <LinearLayout
        android:layout_width="0dp"
        android:layout_weight="3"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="#0093fe">
        <TextView
            android:id="@+id/tv_not_head_title"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:text="歌名"
            android:gravity="center"
            android:textColor="#fff"
            android:textSize="18sp"/>
        <TextView
            android:id="@+id/tv_not_head_content"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:text="歌手"
            android:gravity="center"
            android:textColor="#fff"
            android:textSize="15sp"/>

    </LinearLayout>
<LinearLayout
    android:id="@+id/ll_custom_button"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:layout_weight="2"
    android:background="#334455">
    <ImageView
        android:id="@+id/iv_not_up"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:src="@drawable/btn_prev"
        android:scaleType="centerInside"
       />
    <ImageView
        android:id="@+id/iv_not_play"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:src="@drawable/btn_play"
        android:scaleType="centerInside"/>
    <ImageView
        android:id="@+id/iv_not_next"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:src="@drawable/btn_next"
        android:scaleType="centerInside"/>

</LinearLayout>


</LinearLayout>

2.获取视图对象

 RemoteViews mRemoteViews= new RemoteViews(getPackageName(),R.layout.notification_my_style);
        mRemoteViews.setImageViewResource(R.id.iv_not_head_image,R.mipmap.youname);

        mRemoteViews.setTextViewText(R.id.tv_not_head_title,"应思量");
        mRemoteViews.setTextViewText(R.id.tv_not_head_content,"五色石");
        if( Build.VERSION.SDK_INT <= 9){
            mRemoteViews.setViewVisibility(R.id.ll_custom_button, View.GONE);
        }else{
            mRemoteViews.setViewVisibility(R.id.ll_custom_button, View.VISIBLE);
            if(isPlay){
                mRemoteViews.setImageViewResource(R.id.iv_not_play,R.drawable.btn_pause);
            }else{
                mRemoteViews.setImageViewResource(R.id.iv_not_play,R.drawable.btn_play);
            }
        }

3.设置响应事件 ,这里设置广播来处理点击事件。

 //点击事件处理
        Intent buttonIntent=new Intent(ACTION_BUTTON);
         //头像点击
        buttonIntent.putExtra(INTENT_BUTTONID_TAG,BUTTON_PREV_ID);
        //这里加了广播,所及INTENT的必须用getBroadcast方法
        PendingIntent intent_head_image = PendingIntent.getBroadcast(this, 1, buttonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        mRemoteViews.setOnClickPendingIntent(R.id.iv_not_head_image, intent_head_image);
        //歌名
        buttonIntent.putExtra(INTENT_BUTTONID_TAG,TEXTVIEW_TITLE_ID);
        PendingIntent intent_title = PendingIntent.getBroadcast(this,2,buttonIntent,PendingIntent.FLAG_UPDATE_CURRENT);
        mRemoteViews.setOnClickPendingIntent(R.id.tv_not_head_title,intent_title);
        //歌手
        buttonIntent.putExtra(INTENT_BUTTONID_TAG,TEXTVIEW_CONTENT_ID);
        PendingIntent intent_content = PendingIntent.getBroadcast(this,3,buttonIntent,PendingIntent.FLAG_UPDATE_CURRENT);
        mRemoteViews.setOnClickPendingIntent(R.id.tv_not_head_content,intent_content);

        //上一曲
        buttonIntent.putExtra(INTENT_BUTTONID_TAG,IMAGEVIEW_LEFT_ID);
        PendingIntent intent_left = PendingIntent.getBroadcast(this,4,buttonIntent,PendingIntent.FLAG_UPDATE_CURRENT);
        mRemoteViews.setOnClickPendingIntent(R.id.iv_not_up,intent_left);
        //播放、暂停按钮
        buttonIntent.putExtra(INTENT_BUTTONID_TAG,IMAGEVIEW_CONTENT_ID);
        PendingIntent intent_play= PendingIntent.getBroadcast(this,5,buttonIntent,PendingIntent.FLAG_UPDATE_CURRENT);
        mRemoteViews.setOnClickPendingIntent(R.id.iv_not_play, intent_play);
        //下一曲
        buttonIntent.putExtra(INTENT_BUTTONID_TAG,IMAGEVIEW_RIGHT_ID);
        PendingIntent intent_right= PendingIntent.getBroadcast(this,6,buttonIntent,PendingIntent.FLAG_UPDATE_CURRENT);
        mRemoteViews.setOnClickPendingIntent(R.id.iv_not_next, intent_right);

4.发起Notification

 NotificationManager manager= (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
   NotificationCompat.Builder  builder= new NotificationCompat.Builder(this);
        builder.setContent(mRemoteViews);
        builder.setWhen(System.currentTimeMillis());
        builder.setPriority(NotificationCompat.PRIORITY_DEFAULT);
        builder.setOngoing(true);
        builder.setSmallIcon(R.drawable.a2);
        builder.setAutoCancel(true);
        manager.notify(1, builder.build());
自定义通知

github地址:https://github.com/wangxin3119/MyNotificationDemo

推荐阅读更多精彩内容