今天在做通知的模块。才知道8.0及其以上的系统通知的创建已经不是简单的用 NoticeficationCompat.Builder就可以创建出来的。8.0系统引入了一个消息通道概念----- NotificationChannel。
所以我们需要创建通知的时候,判断下是否是8的系统。以下是完整代码
//1:获取系统提供的通知管理服务
notificationManager = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
//2:如果是8以上的系统,则新建一个消息通道
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setChannerl();
}
private void setChannerl() {
channelId = "chat";//消息通道的id,以后可以通过该id找到该消息通道
String channelName = "聊天消息";//消息通道的name
int importance = NotificationManager.IMPORTANCE_MAX;//通知的优先级
// .具体的请自行百度。作用就是优先级的不同。可以导致消息出现的形式不一样。
// MAX是会震动并且出现在屏幕的上方。设置优先级为low或者min时。来通知时都不会震动,
// 且不会直接出现在屏幕上方
createNotificationChannel(channelId, channelName, importance);
}
@TargetApi(Build.VERSION_CODES.O)
private void createNotificationChannel( String channelId, String channelName,
int
importance) {
NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
notificationManager.createNotificationChannel(channel);
}
然后我是点击按钮来模拟收到通知:
findViewById(R.id.btn_send).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//3:创建通知
createNotification("测试通知");
}
});
private void createNotification( String content) {
Intent intent = new Intent(this, SecondActivity.class);
/*
* 调用PendingIntent的静态放法创建一个 PendingIntent对象用于点击通知之后执行的操作,
* PendingIntent可以理解为延时的Intent,在这里即为点击通知之后执行的Intent
* 这里调用getActivity(Context context, int requestCode, Intent intent, int flag)方法
* 表示这个PendingIntent对象启动的是Activity,类似的还有getService方法、getBroadcast方法
*/
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
NotificationCompat.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//如果是8以上的系统。需要传一个channelId.
builder = new NotificationCompat.Builder(this, "chat");
} else {
builder = new NotificationCompat.Builder(this);
}
builder
.setContentTitle("通知1") // 创建通知的标题
.setContentText(content) // 创建通知的内容
.setSmallIcon(R.drawable.ic_launcher_background) // 创建通知的小图标
.setLargeIcon(BitmapFactory.decodeResource(getResources(),
R.mipmap.ic_launcher)) // 创建通知的大图标
/*
* 首先,无论你是使用自定义视图还是系统提供的视图,上面4的属性一定要设置,不然这个通知显示不出来
*/
.setWhen(System.currentTimeMillis()) // 设定通知显示的时间
.setContentIntent(pi) // 设定点击通知之后启动的内容,这个内容由方法中的参数:PendingIntent对象决定
//.setPriority(NotificationCompat.PRIORITY_MAX) // 设置通知的优先级
.setAutoCancel(true); // 设置点击通知之后通知是否消失
//.setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg"))) // 设置声音
/*
* 设置震动,用一个 long 的数组来表示震动状态,这里表示的是先震动1秒、静止1秒、再震动1秒,这里以毫秒为单位
* 如果要设置先震动1秒,然后停止0.5秒,再震动2秒则可设置数组为:long[]{1000, 500, 2000}。
* 别忘了在AndroidManifest配置文件中申请震动的权限
*/
builder.setVibrate(new long[]{1000, 500, 2000});
/*
* 设置手机的LED灯为蓝色并且灯亮2秒,熄灭1秒,达到灯闪烁的效果,不过这些效果在模拟器上是看不到的,
* 需要将程序安装在真机上才能看到对应效果,如果不想设置这些通知提示效果,
* 可以直接设置:setDefaults(Notification.DEFAULT_ALL);
* 意味将通知的提示效果设置为系统的默认提示效果
*/
//.setLights(Color.BLUE, 2000, 1000)
Notification notification = builder.build(); // 创建通知(每个通知必须要调用这个方法来创建)
/*
* 使用从系统服务获得的通知管理器发送通知,第一个参数是通知的id,不同的通知应该有不同的id,
* 这样当我们要取消哪条通知的时候我们调用notificationManager(通知管理器).cancel(int id)
* 方法并传入发送通知时的对应id就可以了。在这里如果我们要取消这条通知,
* 我们调用notificationManager.cancel(1);就可以了
* 第二个参数是要发送的通知对象
*/
notificationManager.notify(1, notification);
到此。就创建出来一个通知了。我们可以在8.0以上的手机找到设置--》应用和通知---》应用信息---》找到你的那个应用---》应用通知就可以看到会有个类别。这里面的列表就是我们在应用里面创建的应用通道。你可以点击通道查看详情。
点击运行,我们可以看到通知可以正常的弹出来。可是对比一下就可以看到。在8以下的系统上。消息的震动我们是可以控制的。以前我们只要把:
builder.setVibrate(new long[]{1000, 500, 2000});
修改成
builder.setVibrate(new long[]{0});
就可以不震动了。可是这个方法在8.0的设备上并没有起作用。写了以后还是会震动。最后通过查看资料发现。8.0以后。消息的震动就不再是修改builder就可以的。我们需要修改消息通道的属性,代码如下:
@TargetApi(Build.VERSION_CODES.O)
private void createNotificationChannel(boolean isVibrate, String channelId, String channelName,
int
importance) {
NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
//NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
if (isVibrate) {
// 设置通知出现时的震动(如果 android 设备支持的话)
channel.enableVibration(true);
channel.setVibrationPattern(pattern);
} else {
// 设置通知出现时不震动
channel.enableVibration(false);
channel.setVibrationPattern(new long[]{0});
}
notificationManager.createNotificationChannel(channel);
}
8.0以下的还是
builder.setVibrate(new long[]{0});
即可。
然后我又发现一个问题。就是channel一旦createNotificationChannel出来以后。你通过代码再去修改他的属性就不再起作用。
因为我界面上有个checkBox。我想实现。勾选以后接受通知的时候就是震动的。不勾选就是不震动的。
刚开始的思路是在cb的setOnCheckedChangeListener方法里面。去修改channel的enableVibration和setVibrationPattern两个属性的值。发现没有任何作用。后来我思考是不是。因为。channel一旦生产出来就是在系统里面了。不能修改了。于是我又在修改之前。根据channelId先去查看查找有没有。如果有。
notificationManager.deleteNotificationChannel(channelId);
我就先删除掉。然后我再重新new.并且create.即代码修改成了:
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
setChannerl(b);
Log.e("zmm", "onCheckedChanged------------>" + b);
}
});
private void setChannerl(boolean checked) {
channelId = "chat";//消息通道的id,以后可以通过该id找到该消息通道
String channelName = "聊天消息";//消息通道的name
int importance = NotificationManager.IMPORTANCE_MAX;//通知的优先级
// .具体的请自行百度。作用就是优先级的不同。可以导致消息出现的形式不一样。
// MAX是会震动并且出现在屏幕的上方。设置优先级为low或者min时。来通知时都不会震动,
// 且不会直接出现在屏幕上方
createNotificationChannel(checked, channelId, channelName, importance);
}
@TargetApi(Build.VERSION_CODES.O)
private void createNotificationChannel(boolean isVibrate, String channelId, String channelName,
int
importance) {
//先删除之前的channelId对应的消息通道.
notificationManager.deleteNotificationChannel(channelId);
//重新new一个消息通道。
NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
//是否震动
if (isVibrate) {
// 设置通知出现时的震动(如果 android 设备支持的话)
channel.enableVibration(true);
channel.setVibrationPattern(pattern);
} else {
// 设置通知出现时不震动
channel.enableVibration(false);
channel.setVibrationPattern(new long[]{0});
}
notificationManager.createNotificationChannel(channel);
}
删除app.然后重新运行。我第一次进来。发消息是没有震动的。正确。然后勾选cb。然后重新点击发送通知。结果通知是接受到了。可是没有震动。。。。气人不!!!气人。。。
仔细看了下。代码。确定不是因为我自己的粗心哪里写错了。那就是我用的哪个方法肯定没有作用。
经过一杯茶的冷静。我在思考会不会是channelId的原因。因为虽然我删除掉了 。但是系统会不会是像一般的后台一样是个假删除。然后再用相同的id去new的时候。系统又把之前的消息通道拿出来了。如果是这样的话。那属性是没办法修改的。为了测试。我把channelId修改成动态的了。我每次勾选cb的时候。i++。然后channelid="chat"+i;为了防止越来越多的channel.我用beforeId记录之前的channelId。然后再新建的时候。先去删除beforeId.然后再新建。代码如下:
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
i++;
setChannerl(b);
Log.e("zmm", "onCheckedChanged------------>" + b);
}
});
private void setChannerl(boolean checked) {
channelId = "chat" + i;//消息通道的id,以后可以通过该id找到该消息通道
String channelName = "聊天消息" + i;//消息通道的name
int importance = NotificationManager.IMPORTANCE_MAX;//通知的优先级
// .具体的请自行百度。作用就是优先级的不同。可以导致消息出现的形式不一样。
// MAX是会震动并且出现在屏幕的上方。设置优先级为low或者min时。来通知时都不会震动,
// 且不会直接出现在屏幕上方
createNotificationChannel(checked, channelId, channelName, importance);
beforeChannelId = channelId;
}
@TargetApi(Build.VERSION_CODES.O)
private void createNotificationChannel(boolean isVibrate, String channelId, String channelName,
int
importance) {
if (!TextUtils.isEmpty(beforeChannelId)) {
//先删除之前的channelId对应的消息通道.
notificationManager.deleteNotificationChannel(beforeChannelId);
}
//重新new一个消息通道。
NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
//是否震动
if (isVibrate) {
// 设置通知出现时的震动(如果 android 设备支持的话)
channel.enableVibration(true);
channel.setVibrationPattern(pattern);
} else {
// 设置通知出现时不震动
channel.enableVibration(false);
channel.setVibrationPattern(new long[]{0});
}
notificationManager.createNotificationChannel(channel);
}
别忘了修改createNotification()方法里面的
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder = new NotificationCompat.Builder(this, channelId);//该处写的应该是当前的channelId。
} else {
builder = new NotificationCompat.Builder(this);
}
然后重新运行。第一次。发通知。没有震动。OK的。勾选震动。发通知。震动了。OK的!
至此问题就解决了。为了一探究竟。想看下deleteNotificationChannel源码的实现。发现我没有下载源码。所以看不了。于是去官方文档看了下。
。英语不好就不翻译了。但是还是能看到的。如果你新建的channel和要删除的channel是同一个channelId的话。新建的channel的属性和要删除的那个channel是相同的。。。。。我境界还没达到。不知道这样设计的目的。但是应该有他们的原因。。。
重点1:8.0以上消息震动是通过修改channel来实现的:
if (isVibrate) {
// 设置通知出现时的震动(如果 android 设备支持的话)
channel.enableVibration(true);
channel.setVibrationPattern(pattern);
} else {
// 设置通知出现时不震动
channel.enableVibration(false);
channel.setVibrationPattern(new long[]{0});
}
重点2:channel一旦被create出来。修改属性没有作用,可以通过删除掉。再重新create。但是要记得要删除的channelId和要新建的channelId不能一致.
---------------------
作者:androidzmm
来源:CSDN
原文:https://blog.csdn.net/androidzmm/article/details/80679804
版权声明:本文为博主原创文章,转载请附上博文链接!