通知的创建
前言
小编在前面讲Service的时候用到了通知,还记得我们用来干嘛吗?没错,为了在程序退到后台后前台依然知道该程序的存在,在音乐、地图等APP非常常见。
通知是啥?拿起你的智能机,下拉一下通知栏。看到了吧!
但是,通知的设计初衷是好的,后来却被开发者玩坏了。
开发者为了增加自己的应用程序的打开率,发送各种各样的通知以博取更多的展示机会。作为用户的我们对这些垃圾信息非常厌恶。
虽然Android系统允许我们将某个应用程序的通知完全屏蔽,以防止它一直给我们发送垃圾信息,但是在这些信息中,也可能会有我们关心的内容。比如说我希望收到某个我关注的人的微博更新的消息,但是却不想微博一天到晚给我推一些垃圾信息。再过去,用户没有办法对这些信息做区分,要么同意接受所有信息,要么屏蔽所有信息,这也是Android通知功能的痛点。后来……
通知渠道
后来,Android8.0之后引入了通知渠道。
通知渠道就是每条通知都要属于一个对应的渠道。每个应用都可以自由地创建当前应用的通知渠道,但是这些通知渠道的控制权是掌握在用户手上的。用户可以自由地选择这些通知渠道的重要程度,是否响铃、是否振动或者是否要关闭这个渠道的通知。
拥有了控制权之后,用户就再也不用怕那些垃圾通知了,因为用户可以自主地选择关心那些通知。比如,微博可以创建两种通知渠道,一个关注,一个推荐。作为用户的我,就可以关闭推荐的通知渠道。
通知的创建
通知的创建步骤千篇一律,只是因为不同的需求而导致细节不一样。
先贴代码,咱们再逐个讲解
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager |
首先需要一个
NotificationManager
对通知进行管理,可以通过调用Context的getSystemService()
方法获取。getSystemService()
方法接收一个字符串参数用于确定获取系统的哪个服务,这里我们传入Context.NOTIFICATION_SERVICE
即可;创建通知渠道
NotificationChannel
,需要至少三个参数(渠道Id,渠道名称,重要等级)- 渠道Id,自定义,只要全局唯一就可以;
- 渠道名称,展示给用户看的
- 重要等级:有
IMPORTANCE_HIGH、IMPORTANCE_DEFAULT、IMPORTANCE_LOW,IMPORTANCE_MIN
这几种,对应的重要程度一次从高到低。不同的通知等级会决定通知的不同行为。比如QQ的消息通知就是高重要等级,会弹出横幅、发出声音。
因为
NotificationChannel
类和createNotificationChannel()
方法都是Android8.0系统中新增的API,所以在使用的时候还需要加上一个版本判断Build.VERSION.SDK_INT>=Build.VERSION_CODES.O
。构建通知
需要一个Builder构造器来构建Notification对象,但问题在于,Android系统每一个版本都会对通知进行或多或少的修改,API不稳定问题凸显的尤为严重,所以AndroidX库中提供了
NotificationCompat
类,使用这个类的构造器创建Notification对象,就可以保证我们的程序在所有Android系统版本上能够正常工作了(AndroidX中很多xxxCompat
类都是为了版本兼容)然后就是一堆set方法,大家看名字应该就能看出来是干嘛的。
以上工作都完成后,只需要调用
NotificationManager
的notify()
方法就可以让通知显示出来了。notify()
接收两个参数:第一个参数是id,要保证为每个通知指定的id都是不同的,第二个则是Notification对象,这里直接将我们刚刚创建好的Notification对象传入即可。但是如果仅仅按上述步骤操作,我们的通知仅仅起显示的作用,那么像我们平时收到的通知都是可以点击再进入应用的,细心的你应该发现了上述代码中还有一个关键的东西没提到——
PendingIntent
。PendingIntent,从名字上就知道是一个特殊的Intent。它们都能指明某一个“意图”,都可以用于启动Activity、启动Service以及发送广播等。不同的是,Intent倾向于立即执行某个动作,而PendingIntent倾向于在某个合适的时机执行某个动作。所以,也可以把PendingIntent简单理解为延迟执行的Intent。
PendingIntent
的用法同样很简单,主要提供了几个静态方法用于获取PendingIntent的实例,可以根据要求来选择是使用getActivity()、getBroadcast(),还是getService()方法。接收的参数都是相同的:- 第一个参数是Context
- 第二个参数一般用不到,传0即可
- 第三个参数是Intent,把我们的Intent创建传入即可
- 第四个参数用于确定PendingIntent的行为,有
FLAG_ONE_SHOT、FLAG_NO_CREATE、FLAG_CANCEL_CURRENT和FLAG_UPDATE_CURRENT
这4个值可选,具体请查看官网使用文档,通常情况下传0即可。
还有一点,我们还需要让系统状态栏的图标消失(也就是我们上方设置的smallIcon),不然的话这个小图标就一直悬挂着。
有两种解决方案:
第一种:像上方代码一样
setAutoCancel(true)
第二种:调用
manager.cancel(ID)
,还记得我们在发起通知时manager.notify(NOTIFY_ID,notification)
吗?没错,传入的ID就是这里传入的NOTIFY_ID
,当然这个ID是自创的唯一的,看下方代码就明白了。class MainActivity : AppCompatActivity() {
companion object{
const val NOTIFY_ID = 1
}
private lateinit var binding:ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.cancel(NOTIFY_ID)
...
binding.sendNotification.setOnClickListener {
...
manager.notify(NOTIFY_ID,notification)
}
}
}
来看效果展示:
通知的进阶技巧
当然,在上面我们只讲述了基本的通知创建,NotificationCompat.Builder
中还提供了非常丰富的API,以便我们展示更好的通知效果。我们来学习一些常用的API。
先来看看
setStyle()
方法,这个方法允许我们构建出富文本的通知内容。也就是说,通知中不光可以有文字和图标,还可以包含很多东西。setStyle()
方法接收一个NotificationCompat.Style
参数,这个参数就是用来构建具体的富文本信息的,比如长文字、图片等。
val notification = NotificationCompat.Builder(this,"channelId") |
看下方效果,可以明显看出与setContentText
的区别,能够显示完全部文字,而不是以省略号结尾。
还能设置大图片,通过
NotificationCompat.BigPictureStyle
对象,这个对象就是用于设置大图片的,然后调用它的bigPicture()
方法并将图片传入。
val notification = NotificationCompat.Builder(this,"channelId") |
总结
好了,我欠的一篇关于通知的文章就完成了。其实通知的创建步骤是固定的,只是因为我们的不同需求而处理更多的细节。
再来回忆一下创建通知的3步:1、创建NotificationManager;2、创建通知渠道NotificationChannel;3、通过NotificationCompat.Builder创建通知实体。
参考:《第一行代码》