简介
Android 8.0 系统引入了通知渠道的概念。
那什么是通知渠道呢?
意思就是每条通知都要属于一个对应的渠道。每个app可以任意创建不同的通知渠道,但这些通知渠道的控制权掌握在用户手中,是否启动由用户决定。
举个例子:
一个app拥有推荐和关注两种类型的通知,那么用户可以选择关闭推荐的通知,保留关注的通知,这就减少了用户并不关心的通知的打扰。下图是QQ的通知类型:
注: 通知渠道一旦创建好后就不能再修改了,所以再创建之前一定要分析好自己app所需的通知类型。
创建通知
第一步 创建通知渠道
需要一个NotificationManeger对通知进行管理,通过调用Context的getSystemService()方法获取,此方法需要传入一个字符串参数用于确定获取的系统服务,所以这里就传入Context.NOTIFICATION_SERVICE。代码如下:
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
接着就使用NotificationChannel类来构建一个通知渠道,并调用NotificationManager的createNotificationChannel()方法完成创建,由于这个类和这个方法是Android 8.0加入的,所以在使用时还需要判断版本。如下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT)
manager.createNotificationChannel(channel)
}
创建一个通知渠道需要三个参数:渠道ID,渠道名称,重要级别。
- 渠道ID:自由定义,全局唯一即可,是一个string。
- 渠道名称:给用户看到,让用户知道这是关于哪种类型的通知。
- 重要等级:4种,分别为HIGI,DEFAULT,LOW,MIN。用户是可以更改该重要等级的。
创建通知渠道的代码只有在第一次执行的时候才会创建,下次再执行此创建代码时,系统会检测到该通知渠道已经存在了,所以不会重复创建。
第二步 使用通知
通知可以在Activity,BroadcastReceiver,Service里创建,一般不在Activity里创建。具体步骤:
- 使用Builder构造器创建Notification对象,AndroidX库中提供了NotificationCompat类,这个类创建的Notification对象可以保证我们的程序在所有的Android系统上运行,代码如下:
val notification = NotificationCompat.Builder(context, channelId).build()
- 目前这个notification对象还只是一个空的,现在需要给它来添加一些设置。下面的setSmallIcon()方法用于设置通知的小图标,只能使用纯alpha图层的图片,它显示在系统状态栏上;而setLargeIcon()方法用于设置通知的大图标,下拉系统状态栏时可以看到。
val notification = NotificationCompat.Builder(this, channelId)
.setContentTitle("这是标题")
.setContentText("这是内容")
.setSmallIcon(R.drawable.ic_launcher_background)
.setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.ic_launcher_foreground))
.build()
- 现在就只需要调用NotificationManager的notify()方法就能发出通知了。此方法接收2个参数:第一个是id,需要保证每个通知的id都是不用,此id可用来判断用户点击的是哪一条通知;第二个参数就是刚刚创建的notification对象。代码如下:
manager.notify(1, notification)
注:一般现在的app默认是关闭通知的,如果想快速简单的测试,可以手动去app设置里开启通知。如果想要通过代码判断并去告诉并引导用户开启通知功能,可以参考下面这一篇文章。
https://www.jianshu.com/p/3134c5c629ef
第三步 点击通知处理
PendingIntent
我们知道Intent可以代表意图,代表去执行某个动作,而点击通知也是需要去执行一些事情,应该也需要用到Intent,所以这里就需要用到和Intent类似的PendingIntent。Pending即“待定的”,代表等待执行的Intent。
获取PendingIntent
有以下几个获取方法:getActivity(),getBroadcast(),getService()。
它们接收的参数是相同的:
- 第一个是Context
- 第二个是requestCode
- 第三个是Intent对象
- 第四个是PendingIntent的状态
- FLAG_CANCEL_CURRENT:如果当前系统已经存在一个相同的PendingIntent对象了,那么就会将这个对象先取消,再重新生成一个新的PendingIntent对象。
- FLAG_NO_CREATE:如果当前系统不存在相同的PendingIntent对象,那么系统就不会创建该PendingIntent对象而是直接返回null。
- FLAG_ONE_SHOT:指定该PendingIntent只会作用一次,该对象通过send()方法触发之后,就会自动调用cancel()方法销毁,如果再次调用send()方法,那么系统就会返回一个SendIntentException。
- FLAG_UPDATE_CURRENT:如果当前系统存在一个相同的PendingIntent对象,那么系统就直接使用这个PendingIntent对象,只不过此时的Intent会更新为最新的。
使用PendingIntent
Notification的构建器中正好有一个setContentIntent()方法,传入一个PendingIntent对象。代码如下:
notification = NotificationCompat.Builder(this, channelId)
.setContentTitle("这是标题")
.setContentText("这是内容")
.setSmallIcon(R.drawable.ic_launcher_background)
.setLargeIcon(
BitmapFactory.decodeResource(
resources,
R.drawable.ic_launcher_foreground
)
)
.setContentIntent(
PendingIntent.getActivity(
this,
0,
Intent(this, NotificationActivity::class.java),
PendingIntent.FLAG_UPDATE_CURRENT
)
)
.setAutoCancel(true)
.build()
setAutoCancel(true)表示点击通知后,状态栏上的图标就消失,默认是不消失的。
也可以调用如下方法让其消失:
manager.cancel(1)
1 就是之前创建notification时的id。
通知的进阶技巧
setStyle()
此方法可以构建出富文本的通知内容,包括长文本,图标,图片等。
构建长文本
通过setContentText()方法设置的文本只能展示一行,多余的显示的是省略号,使用如下方法就能展示长文本:
.....
.setAutoCancel(true)
.setStyle(
NotificationCompat.BigTextStyle()
.bigText("在这项研究中,斯坦福大学的一个研究小组提出了时间控制 (TC),这种语言模型通过潜在的随机过程进行隐式计划,并生成与该潜在计划一致的文本,以提高长文本生成的性能。")
)
.build()
构建大图片
用法基本相似,如下:
....
.setAutoCancel(true)
.setStyle(
NotificationCompat.BigPictureStyle().bigPicture(
BitmapFactory.decodeResource(resources, R.drawable.bigimage)
)
)
.build()
重要等级
通知的不同重要等级表现的方式不同,高级别的通知就会像社交软件一样,收到消息时发出声音、弹出消息横幅,直接显示在屏幕上方;而低级别的通知还可能会被隐藏。
注:只有在创建通知渠道的时候指定重要等级,并且通知渠道一旦创建,就不能再通过代码进行更改了,而用户可以自由修改通知的等级,开发者无权干预。
所以此时我们需要重新创建一个通知渠道来测试高等级的通知是什么样的。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
....
val channel2 =
NotificationChannel(
channelId2,
channelName2,
NotificationManager.IMPORTANCE_HIGH
)
manager.createNotificationChannel(channel2)
}
notification = NotificationCompat.Builder(this, channelId2)
....
.build()
开启通知横幅
代码即是如此,不过目前手机厂商都会默认关闭应用的通知横幅,所以这里还需要用户去手动开启,否则无法生效。如下图: