通知(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 创建通知的步骤
- 创建一个通知管理类NotificationManager,通过调用 getSystemService()的方法获得。getSystemService方法接收一个字符串参数用于确定获取系统的哪个服务,传入Context.NOTIFICATION_SERVICE
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- 使用Builder构造器创建Notification对象。这里使用 support-v4库中提供的NotificationCompat
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context);
或者这样写:
Notification notification = NotificationCompat.Builder(context).builder();
- 对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
设置通知栏PendingIntent(点击动作事件等都包含在这里)。PendingIntent 从名字上看和Intent 很像,它们都指明一个意图,都可以开启活动,开启服务和发送广播。但是Intent 倾向于立即执行某个动作,而PendingIntent 倾向于某个时机执行动作。
最后一步,发送通知请求
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());