Android 8.0或其以上的系统上的通知的创建和取消通知震动

今天在做通知的模块。才知道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 
版权声明:本文为博主原创文章,转载请附上博文链接!

你可能感兴趣的:(android)