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是相同的。。。。。我境界还没达到。不知道这样设计的目的。但是应该有他们的原因。。。

重点18.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不能一致.

我也好久没写博客了。。之前一个月。忙着交接工作。辞职。搬家。找工作。好在。一切都再慢慢步入正轨。从一个城市到另一个城市。说后悔谈不上。不舍却有的。只是在想。是不是当初可以有更好的选择。不过回到合肥以后。确定开心了很多。在这个城市。有很多我熟悉的朋友。还有一个待我很好的朋友。总是去她家蹭饭。而且一次噩梦也没有做过。离家也近了很多。而且。在这里。我不会觉得害怕。不会觉得孤单。虽然。新公司里面我还不熟悉。但是大家看着就是很好的人。我应该可以和他们好好好相处。。最后但愿我在新公司里面可以多学点东西。嗯。接下来的日子请继续加油!!!

每日语录:

决心走一条路的时候,就不要左顾右盼,风景再美也别流连,你应当清楚自己的目的,你应当清楚你心如钢铁地追求的东西是什么,在哪里,时不时给自己提个醒。加油!
单曲循环《这些年来》





  • 6
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
Android 8.0 及以上版本,为了增强应用程序的安全性,Android 引入了后台限制,禁止未在前台运行的应用程序启动服务。如果您想在后台启动服务,需要使用 `startForegroundService()` 方法。这个方法会启动一个前台服务,然后你可以在服务启动后在通知栏显示一个通知,以此来告知用户服务正在运行。 以下是一个使用 `startForegroundService()` 的示例代码: ``` if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 创建一个 NotificationChannel NotificationChannel channel = new NotificationChannel("channel_id", "channel_name", NotificationManager.IMPORTANCE_DEFAULT); // 向系统注册 NotificationChannel NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.createNotificationChannel(channel); } // 创建一个 Intent,启动你的服务 Intent serviceIntent = new Intent(this, YourService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 在 Android 8.0 及以上版本上,需要调用 startForegroundService() 方法启动服务。 startForegroundService(serviceIntent); } else { // 在 Android 8.0 以下版本上,可以直接调用 startService() 方法启动服务。 startService(serviceIntent); } ``` 注意:如果你使用的是 `startForeground()` 方法,会在 Android 8.0 及以上版本上抛出 `IllegalStateException` 异常,因为 Android 8.0 及以上版本禁止在后台启动服务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值