Android10.0通知Notification的使用这一篇就够了 - CSDN博客

文章推薦指數: 80 %
投票人數:10人

不同android版本上通知功能; 通知的结构; 创建通知; 通知的操作; 从通知启动Activity; 展开式通知; 通知渠道; 通知的级别; 自定义通知. Android10.0通知Notification的使用这一篇就够了 mashanshui 于 2020-04-2414:19:45 发布 27706 收藏 224 分类专栏: android 文章标签: android view notification 通知 版权声明:本文为博主原创文章,遵循CC4.0BY-SA版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/shanshui911587154/article/details/105683683 版权 android 专栏收录该内容 27篇文章 2订阅 订阅专栏 文章目录 前言通知概述不同android版本上通知功能通知的结构创建通知1.创建渠道2.设置点击事件3.构造Notification对象并显示通知 通知的操作1.添加操作按钮2.添加进度条3.设置锁定屏幕公开范围4.更新通知5.移除通知 从通知启动Activity1.单独任务栈2.完整任务栈 展开式通知1.添加大图片2.添加大文本3.收件箱样式的通知 通知渠道通知的级别自定义通知1.为内容区域创建自定义布局2.创建完全自定义的通知布局 总结 前言 最近一段时间写的都是android源码的文章,前几天在公司做了一个需求是关于前台服务的,在写前台服务的时候深入使用到了通知,今天就先写一篇文章总结一下通知的相关内容,后面有时间了在介绍一下前台服务的相关内容。

通知概述 本篇文章主要介绍通知的以下知识点: 不同android版本上通知功能通知的结构创建通知通知的操作从通知启动Activity展开式通知通知渠道通知的级别自定义通知 上面的这么多内容基本覆盖了通知百分之八十的知识点,了解这些足够日常通知的使用了。

不同android版本上通知功能 Android4.1(API级别16) 引入了展开式通知模板(称为通知样式),可以提供较大的通知内容区域来显示信息。

用户可以使用单指向上/向下滑动的手势来展开通知。

Android5.0(API级别21) 引入了锁定屏幕和浮动通知。

向API集添加了通知是否在锁定屏幕上显示的方法(setVisibility()),以及指定通知文本的“公开”版本的方法。

添加了setPriority()方法,告知系统该通知应具有的“干扰性”(例如,将其设置为“高”,可使该通知以浮动通知的形式显示)。

Android7.0(API级别24) 用户可以使用内联回复直接在通知内回复(用户可以输入文本,然后将其发送给通知的父级应用)。

Android8.0(API级别26) 现在必须将单个通知放入特定渠道中。

用户现在可以按渠道关闭通知,而不是关闭应用的所有通知。

包含活动通知的应用会在应用图标上方显示通知“标志”。

(小圆点或数字)用户可以暂停抽屉式通知栏中的通知。

您可以为通知设置自动超时。

可以设置通知的背景颜色。

通知的结构 小图标:此为必要图标,通过setSmallIcon()设置。

应用名称:此由系统提供。

时间戳:此由系统提供,不过您可以通过setWhen()进行替换,或使用setShowWhen(false)将其隐藏。

大图标:此为可选图标(通常仅用于联系人照片;请勿将其用于应用图标),通过setLargeIcon()设置。

标题:此为可选内容,通过setContentTitle()设置。

文本:此为可选内容,通过setContentText()设置。

创建通知 为了在不同的android版本中兼容通知,android在support-compat包中提供了NotificationCompat和NotificationManagerCompat来帮助我们更加方便的使用通知。

由于我们是在android10上使用通知,所以我们必须兼容所有的android版本,那么我们创建通知的步骤就如下: 创建渠道:在android8.0以上需要创建,以下不用创建设置点击事件构造Notification对象并显示通知 1.创建渠道 由于我们只需要在android8.0以上创建,所以在代码中进行判断: privateStringcreateNotificationChannel(StringchannelID,StringchannelNAME,intlevel){ if(android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.O){ NotificationManagermanager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE); NotificationChannelchannel=newNotificationChannel(channelID,channelNAME,level); manager.createNotificationChannel(channel); returnchannelID; }else{ returnnull; } } 这里封装了一个方法,如果api大于android8.0就创建渠道返回渠道id,否则返回空。

这里我只传了三个必要的参数,还有其他的设置在通知渠道那一节单独介绍。

2.设置点击事件 每个通知都应该对点按操作做出响应,通常是在应用中打开对应于该通知的Activity。

为此,您必须指定通过PendingIntent对象定义的内容Intent,并将其传递给setContentIntent()。

Intentintent=newIntent(this,Main2Activity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK); PendingIntentpendingIntent=PendingIntent.getActivity(this,0,intent,0); 3.构造Notification对象并显示通知 Intentintent=newIntent(this,Main2Activity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK); PendingIntentpendingIntent=PendingIntent.getActivity(this,0,intent,0); StringchannelId=createNotificationChannel("my_channel_ID","my_channel_NAME",NotificationManager.IMPORTANCE_HIGH); NotificationCompat.Buildernotification=newNotificationCompat.Builder(this,channelId) .setContentTitle("通知") .setContentText("收到一条消息") .setContentIntent(pendingIntent) .setSmallIcon(R.mipmap.ic_launcher) .setPriority(NotificationCompat.PRIORITY_HIGH) .setAutoCancel(true); NotificationManagerCompatnotificationManager=NotificationManagerCompat.from(this); notificationManager.notify(100,notification.build()); 这里通过NotificationCompat.Builder构造通知需要的信息,注意这里调用了setAutoCancel(true),它会在用户点按通知后自动移除通知,如果不调用或者传参数为false就会在点击后依然存在,但是如果用户清除下拉框的所有消息会把这样的通知清理掉。

如果不想用户把他清理掉呢?可以调用setOngoing(true)方法,这样除非你的app死掉或者在代码中取消,否则他都不会消失。

通知的操作 1.添加操作按钮 一个通知最多可以提供三个操作按钮,让用户可以快速响应,例如暂停提醒,甚或回复短信。

但这些操作按钮不应该重复用户在点按通知时执行的操作。

要添加操作按钮,请将PendingIntent传递给addAction()方法。

这就像是设置通知的默认点按操作,不同的是不会启动Activity,而是可以完成各种其他任务,例如启动在后台执行作业的BroadcastReceiver,这样该操作就不会干扰已经打开的应用。

IntentsnoozeIntent=newIntent(this,MyBroadcastReceiver.class); snoozeIntent.setAction(ACTION_SNOOZE); snoozeIntent.putExtra(EXTRA_NOTIFICATION_ID,0); PendingIntentsnoozePendingIntent= PendingIntent.getBroadcast(this,0,snoozeIntent,0); NotificationCompat.Buildernotification=newNotificationCompat.Builder(this,channelId) .setContentTitle("通知") .setContentText("收到一条消息") .setContentIntent(pendingIntent) .setSmallIcon(R.mipmap.ic_launcher) .setPriority(NotificationCompat.PRIORITY_HIGH) .addAction(R.drawable.icon,"按钮",snoozeIntent) .setAutoCancel(true); 2.添加进度条 通知可以包含动画形式的进度指示器,向用户显示正在进行的操作状态。

通过setProgress(max,progress,false)方法来设置和更新进度 第一个参数进度的最大值第二个参数是当前进度值第三个参数是是否是确定性进度条,具体意思看我下面的例子 NotificationCompat.Buildernotification=newNotificationCompat.Builder(this,channelId) .setContentTitle("通知") .setContentText("收到一条消息") .setContentIntent(pendingIntent) .setSmallIcon(R.mipmap.ic_launcher) .setPriority(NotificationCompat.PRIORITY_HIGH) .addAction(R.drawable.icon,"按钮",pendingIntent) .setAutoCancel(true); //Issuetheinitialnotificationwithzeroprogress intPROGRESS_MAX=100; intPROGRESS_CURRENT=0; notification.setProgress(PROGRESS_MAX,PROGRESS_CURRENT,false); NotificationManagerCompatnotificationManager=NotificationManagerCompat.from(this); notificationManager.notify(100,notification.build()); 上面对进度条进行了初始化,然后不断调用下面的方法进行更新: //更新 notification.setContentText("Downloadcomplete") .setProgress(0,0,false); notificationManager.notify(100,notification.build()); 上面的例子是一个确定性的进度条,这个怎么理解呢,我给你们看一个不确定性的进度条你们就知道了,将第三个参数设置为true,效果如下: 3.设置锁定屏幕公开范围 要控制锁定屏幕中通知的可见详情级别,请调用setVisibility()并指定以下值之一: VISIBILITY_PUBLIC显示通知的完整内容。

VISIBILITY_SECRET不在锁定屏幕上显示该通知的任何部分。

VISIBILITY_PRIVATE显示基本信息,例如通知图标和内容标题,但隐藏通知的完整内容。

4.更新通知 要在发出此通知后对其进行更新,请再次调用NotificationManagerCompat.notify(),并将之前使用的具有同一ID的通知传递给该方法。

如果之前的通知已被关闭,则系统会创建一个新通知。

您可以选择性调用setOnlyAlertOnce(),这样通知只会在通知首次出现时打断用户(通过声音、振动或视觉提示),而之后更新则不会再打断用户。

5.移除通知 除非发生以下情况之一,否则通知仍然可见: 用户关闭通知。

用户点击通知,且您在创建通知时调用了setAutoCancel()。

您针对特定的通知ID调用了cancel()。

此方法还会删除当前通知。

您调用了cancelAll()方法,该方法将移除之前发出的所有通知。

如果您在创建通知时使用setTimeoutAfter()设置了超时,系统会在指定持续时间过后取消通知。

如果需要,您可以在指定的超时持续时间过去之前取消通知。

从通知启动Activity 通知的点击操作是由PendingIntent实现的,通过PendingIntent可以跳转Activity,开启服务,发送广播,我们着重来讲一下跳转Activity的操作,跳转分为两种类型,一是这个Activity单独在一个任务栈中,点击返回就直接返回到桌面;二是这个Activity拥有一个定义好的返回栈,点击返回会根据任务栈顺序进行回退。

1.单独任务栈 由于从通知启动的“特殊Activity”不需要返回堆栈,因此您可以通过调用getActivity()来创建PendingIntent,但您还应确保在清单中定义了相应的任务选项。

在清单中,将以下属性添加到元素中。

android:taskAffinity="" 与您将在代码中使用的FLAG_ACTIVITY_NEW_TASK标记结合使用,将此属性设置为空可以确保这类Activity不会进入应用的默认任务。

具有应用默认相似性的任何现有任务都不会受到影响。

android:excludeFromRecents=“true” 用于从“最近”中排除新任务,以免用户意外返回它。

Intentintent=newIntent(this,Main2Activity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK); PendingIntentpendingIntent=PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT); 2.完整任务栈 定义应用的Activity层次结构通过向应用清单文件中的每个元素添加android:parentActivityName属性,定义Activity的自然层次结构。

例如: ... 构建包含返回堆栈的PendingIntent要启动包含Activity的返回堆栈的Activity,您需要创建TaskStackBuilder的实例并调用addNextIntentWithParentStack(),向其传递您要启动的Activity的Intent。

只要您为每个Activity定义了父Activity(如上文所述),就可以调用getPendingIntent()来接收包含整个返回堆栈的PendingIntent。

IntentresultIntent=newIntent(this,ResultActivity.class); TaskStackBuilderstackBuilder=TaskStackBuilder.create(this); stackBuilder.addNextIntentWithParentStack(resultIntent); PendingIntentresultPendingIntent= stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT); 如有必要,您可以通过调用TaskStackBuilder.editIntentAt()向堆栈中的Intent对象添加参数。

有时候需要这样做,以确保返回堆栈中的Activity在用户向上导航到它时显示有意义的数据。

展开式通知 基本通知通常包括标题、一行文本,以及用户可以执行的一项或多项响应操作。

要提供更多信息,您还可以应用本页介绍的多个通知模板之一来创建大型展开式通知。

1.添加大图片 NotificationCompat.Buildernotification=newNotificationCompat.Builder(this,channelId) .setContentTitle("通知") .setContentText("收到一条消息") .setContentIntent(pendingIntent) .setSmallIcon(R.mipmap.ic_launcher) .setPriority(NotificationCompat.PRIORITY_HIGH) .setStyle(newNotificationCompat.BigPictureStyle() .bigPicture(BitmapFactory.decodeResource(getResources(),R.drawable.image))) .setAutoCancel(true); 这里通过setStyle来使用系统提供的模版创建大图片通知,要使该图片仅在通知收起时显示为缩略图,请调用setLargeIcon()并传入该图片,同时调用BigPictureStyle.bigLargeIcon()并传入null,这样大图标就会在通知展开时消失: NotificationCompat.Buildernotification=newNotificationCompat.Builder(this,channelId) .setContentTitle("通知") .setContentText("收到一条消息") .setContentIntent(pendingIntent) .setSmallIcon(R.mipmap.ic_launcher) .setPriority(NotificationCompat.PRIORITY_HIGH) .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.image)) .setStyle(newNotificationCompat.BigPictureStyle() .bigPicture(BitmapFactory.decodeResource(getResources(),R.drawable.image)) .bigLargeIcon(null)) .setAutoCancel(true); 2.添加大文本 应用NotificationCompat.BigTextStyle,以在通知的展开内容区域显示文本: NotificationCompat.Buildernotification=newNotificationCompat.Builder(this,channelId) .setContentTitle("通知") .setContentText("收到一条消息") .setContentIntent(pendingIntent) .setSmallIcon(R.mipmap.ic_launcher) .setPriority(NotificationCompat.PRIORITY_HIGH) .setStyle(newNotificationCompat.BigTextStyle() .bigText("无论是否意识到Gradle的存在,每位Android程序员都会直接或间接的与Gradle打交道。

每当通过AndroidStudio新建一个工程时,AS都会自动创建一个通用的目录结构,然后就可以进行开发,在app的build.gradle中添加一些依赖,点击右上角的SyncNow")) .setAutoCancel(true); 3.收件箱样式的通知 如果您想要添加多个简短的摘要行(例如收到的电子邮件的片段),可对通知应用NotificationCompat.InboxStyle。

这样,您就可以添加多条内容文本,并且每条文本均截断为一行,而不是显示为NotificationCompat.BigTextStyle提供的一行连续文本。

要添加新行,最多可调用addLine()6次。

如果添加的行超过6行,则仅显示前6行。

NotificationCompat.Buildernotification=newNotificationCompat.Builder(this,channelId) .setContentTitle("通知") .setContentText("收到一条消息") .setContentIntent(pendingIntent) .setSmallIcon(R.mipmap.ic_launcher) .setPriority(NotificationCompat.PRIORITY_HIGH) .setStyle(newNotificationCompat.InboxStyle() .addLine("无论是否意识到Gradle的存在,每位Android程序员都会直接或间接的与Gradle打交道。

每当通过AndroidStudio新建一个工程时") .addLine("AS都会自动创建一个通用的目录结构,然后就可以进行开发,在app的build.gradle中添加一些依赖,点击右上角的SyncNow") .addLine("编写代码,点击绿色小箭头Run运行代码,一切都这么美好")) .setAutoCancel(true); 通知渠道 从Android8.0(API级别26)开始,所有的通知都必须分配到相应的渠道。

对于每个渠道,您可以设置应用于其中的所有通知的视觉和听觉行为(也就是通知的级别)。

然后,用户可以更改这些设置,并确定您应用中的哪些通知渠道应具有干扰性或应该可见。

我认为添加这个功能主要是为了让用户能够更透明的管理通知。

(百分之九十九的人都不知道,知道也不会去看,唉!!!)我们来看一下酷狗音乐的通知渠道情况(不同的手机厂商系统不同显示会有出入):可以看到酷狗总共有5个通知渠道,我们看一下酷狗推送消息这个渠道:渠道详情里有重要程度(也就是通知的级别)、提示音、震动等设置,这些都是我们可以在代码中设置的,当然用户也可以主动的修改他们。

前面已经讲了通知渠道的创建,下面来看一下创建的时候可以做哪些额外操作: NotificationManagermanager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE); NotificationChannelchannel=newNotificationChannel(channelID,channelNAME,level); //设置提示音 channel.setSound(); //开启指示灯 channel.enableLights(); //开启震动 channel.enableVibration(); //设置锁屏展示 channel.setLockscreenVisibility(); //设置渠道描述 channel.setDescription(); manager.createNotificationChannel(channel); 这里只列举了一部分,在Android7.1(API级别25)以下这些都是直接在NotificationCompat.Builder中设置的,只是在Android8.0(API级别26)上把这些功能拆分到了渠道设置上。

在创建了渠道之后就无法更改这些设置了。

这里需要单独讲一下,无论我们调用多少次创建渠道的方法,对于同一个渠道ID只有第一次创建是有效的,因为创建的时候会去判断是否存在这个渠道,如果存在是不会重新创建的。

其实这么说也不完全对,有兴趣的可以看一下我在文章最后做的一个分析。

虽然在创建渠道之后我们不能再去修改他,但是我们可以获取渠道设置,因为渠道设置对用户是透明的,用户可以去随意的设置他,所以我们可以在获取渠道设置之后引导用户设置我们想要的行为。

比如我是微信的开发者,微信的通知被用户手动关掉了,我在检测到通知被关之后就会去告诉用户这个通知很重要不能关掉,然后引导用户跳到那个页面进行设置。

主要的步骤如下: 1.读取通知渠道设置 通过调用getNotificationChannel()或getNotificationChannels()获取NotificationChannel对象。

查询特定的渠道设置,例如getVibrationPattern()、getSound()和getImportance()。

2.打开通知渠道设置 Intentintent=newIntent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS); intent.putExtra(Settings.EXTRA_APP_PACKAGE,getPackageName()); intent.putExtra(Settings.EXTRA_CHANNEL_ID,myNotificationChannel.getId()); startActivity(intent); 注意,该intent需要两个提取项,分别用于指定您应用的软件包名称(也称为应用ID)和要修改的渠道。

其实还有一个渠道分组没讲,但是用的很少就不说了。

通知的级别 通知的级别主要体现在通知的展示方式上,有的通知只在状态栏现在一个图标,有的通知却会弹出来悬浮在屏幕上(例如微信),这就是通过设置通知的级别实现的。

在Android7.1(API级别25)及更低版本上是通过priority这个属性设置,在Android8.0(API级别26)及更高版本上是通过importance属性设置。

用户可见的重要性级别重要性(Android8.0及更高版本)优先级(Android7.1及更低版本)紧急发出提示音,并以浮动通知的形式显示IMPORTANCE_HIGHPRIORITY_HIGH或PRIORITY_MAX高发出提示音IMPORTANCE_DEFAULTPRIORITY_DEFAULT中不发出提示音IMPORTANCE_LOWPRIORITY_LOW低不发出提示音,且不会在状态栏中显示IMPORTANCE_MINPRIORITY_MIN 1.Android7.1(API级别25)及更低版本通过setPriority(NotificationCompat.PRIORITY_LOW)方法可以直接设置。

2.Android8.0(API级别26)及更高版本在Android8.0中这一功能需要在通知渠道中设置 NotificationChannelchannel=newNotificationChannel(channelID,channelNAME,NotificationManager.IMPORTANCE_LOW); 最后一个参数就是通知的级别,除了在创建渠道的时候设置,在渠道创建完成之后也可以设置 NotificationChannelchannel=newNotificationChannel(channelID,channelNAME,NotificationManager.IMPORTANCE_LOW); channel.setImportance(NotificationManager.IMPORTANCE_LOW); 兼容对比上面两个设置方法,我们发现把这两个设置都加上,并且设置相同的等级就可以兼容所有的版本。

自定义通知 使用自定义通知布局时,请特别注意确保您的自定义布局适用于不同的设备屏幕方向和分辨率。

虽然对于所有界面布局,此建议都适用,但它对通知布局而言尤为重要,因为抽屉式通知栏中的空间非常有限。

自定义通知布局的可用高度取决于通知视图。

通常情况下,收起后的视图布局的高度上限为64dp,展开后的视图布局的高度上限为256dp。

自定义通知有两种,一种是为内容区域创建自定义布局,另一种是创建完全自定义的通知布局。

1.为内容区域创建自定义布局 如果您需要自定义内容区域的布局,可以将NotificationCompat.DecoratedCustomViewStyle应用到您的通知。

借助此API,您可以为通常由标题和文本内容占据的内容区域提供自定义布局,同时仍对通知图标、时间戳、子文本和操作按钮使用系统装饰。

自定义布局的使用方式如下: 构建基本通知(使用NotificationCompat.Builder)调用setStyle(),向其传递一个NotificationCompat.DecoratedMediaCustomViewStyle实例。

将自定义布局扩充为RemoteViews的实例。

调用setCustomContentView()以设置收起后通知的布局。

您还可以选择调用setCustomBigContentView()来为展开后通知设置不同的布局。

StringchannelId=createNotificationChannel("my_channel_ID","my_channel_NAME",NotificationManager.IMPORTANCE_MAX); RemoteViewsnotificationLayout=newRemoteViews(getPackageName(),R.layout.custom_notification_item); RemoteViewsnotificationLayoutExpanded=newRemoteViews(getPackageName(),R.layout.custom_notification_large); NotificationCompat.Buildernotification=newNotificationCompat.Builder(this,channelId) .setSmallIcon(R.mipmap.ic_launcher) .setStyle(newNotificationCompat.DecoratedCustomViewStyle()) .setCustomContentView(notificationLayout) .setCustomBigContentView(notificationLayoutExpanded) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setAutoCancel(true); NotificationManagerCompatnotificationManager=NotificationManagerCompat.from(this); notificationManager.notify(100,notification.build()); 2.创建完全自定义的通知布局 如果您不希望使用标准通知图标和标题装饰通知,请按照上述步骤使用setCustomBigContentView(),但不要调用setStyle()。

要支持低于Android4.1(API级别16)的Android版本,您还应调用setContent(),向其传递同一RemoteViews对象。

总结 在测试创建了渠道之后还能不能修改的时候我发现有些信息是能修改的,但是大部分是不能的,于是我去看了一下创建渠道的源码,结果发现前面说的渠道在创建之后就不能进行修改了其实不完全对,正确的是大部分主要的都不能修改了,有一些次要的信息还是能修改的,看一下创建渠道时发现渠道已经存在处理的代码: NotificationChannelexisting=r.channels.get(channel.getId()); //Keepmostoftheexistingsettings if(existing!=null&&fromTargetApp){ if(existing.isDeleted()){ existing.setDeleted(false); needsPolicyFileChange=true; //logaresurrectedchannelasifit'snewagain MetricsLogger.action(getChannelLog(channel,pkg).setType( com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN)); } //发现渠道名字不同会更新 if(!Objects.equals(channel.getName().toString(),existing.getName().toString())){ existing.setName(channel.getName().toString()); needsPolicyFileChange=true; } //发现渠道描述不同会更新 if(!Objects.equals(channel.getDescription(),existing.getDescription())){ existing.setDescription(channel.getDescription()); needsPolicyFileChange=true; } //我也不知道是什么 if(channel.isBlockableSystem()!=existing.isBlockableSystem()){ existing.setBlockableSystem(channel.isBlockableSystem()); needsPolicyFileChange=true; } //发现组不同会更新 if(channel.getGroup()!=null&&existing.getGroup()==null){ existing.setGroup(channel.getGroup()); needsPolicyFileChange=true; } //Appsareallowedtodowngradechannelimportanceiftheuserhasnotchangedany //fieldsonthischannelyet. //当用户没有手动修改过渠道的信息,并且要更新的通知等级小于现有的等级可以更新 finalintpreviousExistingImportance=existing.getImportance(); if(existing.getUserLockedFields()==0&& channel.getImportance()



請為這篇文章評分?