此 Codelab 是“使用 Kotlin 进行高级 Android 开发”课程的一部分。如果您按顺序学习这些 Codelab,您将会充分发掘课程的价值,但并不强制要求这样做。“使用 Kotlin 进行高级 Android 开发”Codelab 着陆页列出了所有课程 Codelab。
简介
通知是指在应用界面之外向用户显示的消息。当设备处于解锁状态时,通知会显示在屏幕顶部;如果设备处于锁定状态,则显示在锁定屏幕上(具体取决于安全设置)。
典型的通知由标题、说明和图标组成。通知还可以包含可点击的操作、快速回复、可扩展内容和图片。
通知可以及时传送信息,还可以包含可让用户执行快速操作(例如发送回复或暂停闹钟)的按钮。点击通知后,用户会转到与通知内容相关的应用视图。
通过通知功能,您可以提醒用户执行重要任务、告知用户所发生的事情,或者让其在应用处于后台运行时传达重要信息。谨慎使用通知。这样做不仅尊重用户,而且更有可能让您的应用收到应有的关注。
在此 Codelab 中,您将学习如何在 Android 应用中创建和使用通知。
您应当已掌握的内容
您应熟悉以下内容/操作:
- 如何使用 Kotlin 创建 Android 应用。特别是,应使用 Android SDK。
- 如何使用架构组件和数据绑定设计应用架构。
- 对 BroadcastReceiver 有基本的了解
- 对 AlarmManager 有基本的了解
学习内容
- 如何创建通知、设置通知样式以及发送通知。
- 如何取消通知。
- 如何创建通知渠道。
- 如何向通知添加快速操作功能?
- 如何在应用图标上显示通知标志。
您将执行的操作
- 向起始应用添加通知。
- 取消您之前发送的通知。
- 为不同类型的通知创建渠道。
- 在起始应用中自定义通知。
- 添加快速操作即可让您的通知具有互动性。
- 关闭通知标志。
鸡蛋烹饪非常简单,但如果您无法追踪时间,则可能是一项具有挑战性的任务。在此 Codelab 中,您将开发一个鸡蛋计时器应用,让它变得完美,就像您将来的鸡蛋一样。您将首先构建一个工作的鸡蛋计时器应用,该应用可让用户为不同的鸡蛋样式设置不同的烹饪时间设置。计时器从所选的时间间隔开始倒计时,并在鸡蛋准备就绪后显示消息框消息。
这看起来可能很实用,但实际上还算不上完美,而且不太方便用户操作。首先,消息框消息仅显示较短的时间,因此很容易被忽略。此外,如果应用不在前台运行,或者设备处于锁定状态,那么消息框消息消失后,就无法显示计时器状态的视觉指示器。
鸡蛋计时器最好使用通知来提醒用户时间到了。用户一定要知道鸡蛋已经做好了,否则鸡蛋会煮熟!通知是可视的,可以包含声音并使设备振动 - 所有方式都可以吸引用户的注意力!这样,您就可以获得完美的鸡蛋,吃得开心,而且享受美食。
如需获取示例应用,您可以执行以下任一操作:
从 GitHub 克隆代码库并切换到 starter 分支。
$ git clone https://github.com/googlecodelabs/android-kotlin-notifications
或者,您也可以下载 Zip 文件并将其解压缩,然后在 Android Studio 中打开代码库。
- 在 Android Studio 中打开并运行应用。
您将看到一张鸡蛋图片和一个下拉菜单,其中包含烹饪鸡蛋的预定义时间间隔列表。点击软煮下拉菜单的三角形。列表中的第一个选项用于测试目的,并且将闹钟设置为仅 10 秒。列表旁边是一个启动鸡蛋计时器的开关。您随时可以使用此开关启动和停止鸡蛋计时器。起始代码完全有效,这意味着你可以设置鸡蛋计时器,看看它是否倒计时至 0。计时器完成后,系统会显示一条消息框消息,如下所示。
- 检查源代码。起始应用由一个名为
MainActivity
的 Activity 组成。有三个名为receiver
、ui
和util
的子软件包。
- /receiver -
receiver
软件包包含两个名为AlarmReceiver
和SnoozeReceiver
的广播接收器。当用户定义的计时器时间到时,AlarmManager
会触发AlarmReceiver
以发送通知。SnoozeReceiver
处理用户点击以暂停通知的操作。 - /ui - 此文件包含
EggTimerFragment
(应用界面的一部分)。EggTimerViewModel
负责启动和取消计时器,以及其他与生命周期相关的应用任务。 - /util - 此软件包中包含两个文件。
BindingUtils.kt
具有绑定适配器,用于启用应用界面与ViewModel
之间的数据绑定。NotificationUtils.kt
在NotificationManager
上具有扩展方法。
使用通知是吸引用户关注您的应用的绝佳方法。无论您的应用未在前台运行还是在前台运行,通知都会在屏幕顶部显示弹出式窗口,并且可能包含声音或振动。如需创建通知,您需要使用通知构建器并提供标题文本、内容文本和图标。构建器提供所有必要的字段后,NotificationManager
是一种系统服务,可帮助您将此内容显示为通知。NotificationManager
负责发送通知、更新其内容和取消通知。在以下步骤中,您将向 NotificationManager
添加扩展方法。这样,每次您需要使用 NotificationManager
时,就都可以使用这些扩展函数来实现您需要的功能。
第 1 步:创建基本通知
在此任务中,您将创建新通知,为用户设置消息,然后发送该通知。
- 打开
NotificationUtils.kt
类并找到TODO: Step 1.1
。在本 Codelab 和应用代码中,您将找到匹配的待办事项。 - 检查指定的
sendNotification()
函数。您要将此扩展函数扩展到NotificationManager
,以发送通知。
//NotificationUtils.kt
// TODO: Step 1.1 extension function to send messages (GIVEN)
/**
* Builds and delivers a notification.
*
* @param messageBody, notification text.
* @param context, activity context.
*/
fun NotificationManager.sendNotification(messageBody: String, applicationContext: Context) {
- 获取通知构建器的实例,传入应用上下文和渠道 ID。渠道 ID 是渠道的字符串值。
通知渠道是一种通知分组方式。通过将类似类型的通知归为一组,开发者和用户可以控制相应渠道中的所有通知。创建渠道后,该渠道可用于传递任意数量的通知。
//NotificationUtils.kt
// TODO: Step 1.2 get an instance of NotificationCompat.Builder
val builder = NotificationCompat.Builder(
applicationContext,
applicationContext.getString(R.string.egg_notification_channel_id)
)
- 通过设置通知图标来代表您的应用、标题和您要发送给用户的消息的内容文本。您将在 Codelab 中看到进一步自定义通知的更多选项,但这是您至少要设置多少数据才能发送通知。
//NotificationUtils.kt
// TODO: Step 1.3 set title, text and icon to builder
.setSmallIcon(R.drawable.cooked_egg)
.setContentTitle(applicationContext.getString(R.string.notification_title))
.setContentText(messageBody)
- 接下来,您需要使用通知的唯一 ID 以及构建器中的
Notification
对象调用notify()
。
此 ID 代表当前通知实例,更新或取消此通知时需要此 ID。由于您的应用在给定时间内仅有一条有效通知,因此您可以为所有通知使用相同的 ID。在 NotificationUtils.kt
中,您已获得用于此目的的常量,名为 NOTIFICATION_ID
。请注意,由于您可以直接从同一类的扩展函数执行调用,因此您可以直接调用 notify()
。
//NotificationUtils.kt
// TODO: Step 1.4 call notify to send the notification
// Deliver the notification
notify(NOTIFICATION_ID, builder.build())
- 打开
ui/EggTimerViewModel.kt
并找到startTimer()
函数。在用户创建鸡蛋计时器时,此函数创建具有所选时间间隔的闹钟。 - 用户启动计时器时,您将在此函数中触发通知。为了调用您之前实现的
sendNotification()
函数,您需要一个NotificationManager
实例。NotificationManager
是一种系统服务,提供为 Notifications API 提供的所有函数,包括您添加的扩展函数。每当您想要发送、取消或更新通知时,都需要向系统请求NotificationManager
的实例。使用通知消息和上下文调用sendNotification()|
函数。
// EggTimerViewModel.kt
// TODO: Step 1.5 get an instance of NotificationManager
// and call sendNotification
val notificationManager = ContextCompat.getSystemService(
app,
NotificationManager::class.java
) as NotificationManager
notificationManager.sendNotification(app.getString(R.string.timer_running), app)
即将大功告成!不过,如果您现在运行应用并设置计时器,将不会收到通知。
- 打开
logcat
并搜索"No Channel found"
。您应该会看到一条错误消息,指出egg_channel
不存在。在以下步骤中,您将详细了解通知渠道并解决该问题。
第 2 步:通知渠道
从 API 级别 26 开始,必须将所有通知分配给一个渠道。如果您点按并按住应用启动器图标,选择应用信息,然后点按通知,即可看到与该应用相关联的通知渠道列表。由于您的应用尚未创建任何渠道,因此目前该列表为空。
频道代表一种“类型”的通知 - 例如,鸡蛋烹饪时可以发送通知,也可以使用另一个渠道发送每日通知,提醒您在早餐时吃鸡蛋。频道中的所有通知都会归为一组,并且用户可以为整个频道配置通知设置。这样,用户就可以根据自己感兴趣的通知类型,对通知设置进行个性化设置。例如,用户可以停用早餐通知,但仍然选择查看来自计时器的通知。
开发者可对频道中的所有通知应用初始设置、重要性和行为。您设定初始设置后,用户可以覆盖这些设置。
在第 1.1 步中,您使用了 egg_notification_channel_id
作为通知渠道,因此现在您需要实际创建和自定义此渠道的通知设置和行为。
- 打开
EggTimerFragment.kt
并找到createChannel()
函数。 - 将唯一频道 ID 传递给
NotificationChannel
的构造函数。 - 传递通知渠道名称,用户还可以在其设置屏幕中看到该名称。
- 作为最后一个参数,传递通知渠道的重要性级别。本 Codelab 后面会介绍重要性级别,因此目前您可以使用
NotificationManag
er.IMPORTANCE_LOW
。 - 在
notificationChannel
对象上,将enableLights
设置为 true。此设置会在系统显示通知时启用指示灯。 - 在
notificationChannel
对象上,将lightColor
设置为红色,以便在显示通知时显示红灯。 - 在
notificationChannel
对象上,将enableVibration
设置为 true,以启用振动。 - 在
notificationChannel
对象上,将频道说明设置为‘Time for breakf
ast'。 - 通过调用
getSystemService()
获取NotificationManager
的实例。 - 对
NotificationManager
调用createNotificationChannel()
,并传递您在上一步中创建的notificationChannel
对象。
//EggTimerFragment.kt
private fun createChannel(channelId: String, channelName: String) {
// TODO: Step 1.6 START create a channel
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationChannel = NotificationChannel(
channelId,
channelName,
// TODO: Step 2.4 change importance
NotificationManager.IMPORTANCE_LOW
)
// TODO: Step 2.6 disable badges for this channel
notificationChannel.enableLights(true)
notificationChannel.lightColor = Color.RED
notificationChannel.enableVibration(true)
notificationChannel.description = "Time for breakfast"
val notificationManager = requireActivity().getSystemService(
NotificationManager::class.java
)
notificationManager.createNotificationChannel(notificationChannel)
}
// TODO: Step 1.6 END create channel
}
- 接下来,如需创建频道,您需要调用您刚刚编写的
createChannel()
函数(第 1.7 步)。此函数接受两个参数,即渠道 ID 和渠道名称。您需要从项目中已有的字符串资源中查找频道 ID 和频道名称。
// EggTimerFragment.kt
// TODO: Step 1.7 call createChannel
createChannel(
getString(R.string.egg_notification_channel_id),
getString(R.string.egg_notification_channel_name)
)
- 您需要将渠道 ID 传递给通知构建器。您已在第 1.2 步执行此操作。将错误值设为频道 ID 会导致通知失败。打开
NotificationUtils.kt
以验证您之前设置的频道 ID 是否正确。
// NotificationUtils.kt
val builder = NotificationCompat.Builder(
applicationContext,
// TODO: Step 1.8 verify the notification channel name
applicationContext.getString(R.string.egg_notification_channel_id)
)
- 运行应用,您会看到每次启动计时器时该应用都会发送通知。
- 拉取状态栏,并观察通知标题、内容和图标与您在先前步骤中设置的内容保持一致。
- 如需验证新创建的频道,请关闭应用并找到应用图标。长按相应的应用图标,然后选择应用信息。
- 从设置列表中选择通知。您应该会在显示通知设置正下方看到一个名为鸡蛋的新频道。
现在,当您运行应用时,系统会显示通知。作为应用开发者,您的用户可以自定义在此渠道中发送的所有通知的设置和行为。恭喜,您已创建通知!
第 3 步:向应用添加通知
到目前为止,这显示了 Notifications API 的基本用法,但在启动计时器后立即发送通知并没有什么意义。用户更喜欢在鸡蛋准备好时收到通知。在此 Codelab 的以下部分中,您将修复此问题,并将消息框消息更改为通知。
您已发送通知,并观察了向用户显示的通知的方式,但这只是创建优质通知的第一步。在此步骤中,您将更改通知,以便在更合适的时间发送。
您的应用使用 AlarmManager
设置闹钟。起始代码中已提供了与 AlarmManager
相关的代码,用于显示消息框消息。AlarmManager
会跟踪所需的时间选择,并在时间到了时触发 AlarmReceiver.kt
的 onReceive()
函数。如果您打开 AlarmReceiver.kt
并导航到 onReceive()
,则应该会在每次设置鸡蛋计时器时看到消息框消息。
- 打开
AlarmReceiver.kt
(NotificationManager
的实例),并使用消息文本和上下文参数调用sendNotification()
函数。
// AlarmReceiver.kt
// TODO: Step 1.9 add call to sendNotification
val notificationManager = ContextCompat.getSystemService(
context,
NotificationManager::class.java
) as NotificationManager
notificationManager.sendNotification(
context.getText(R.string.eggs_ready).toString(),
context
)
- (可选)移除消息框,因为系统会在计时器到来时您的应用发送通知。
// AlarmReceiver.kt
// TODO: Step 1.10 [Optional] remove toast
// Toast.makeText(
// context,
// context.getText(R.string.eggs_ready),
// Toast.LENGTH_SHORT
// ).show()
- 运行您的应用 。你每次启动计时器以及每次计时器响铃时,都应该会看到一条通知。
这并不理想。您不想向用户发送过多通知。您可以移除在用户启动计时器时发送的第一个通知。
- 打开
EggTimerFragment.kt
并移除第 1.5 步的通知代码。
// EggTimeViewModel.kt
// TODO: Step 1.5 get an instance of NotificationManager
// and call sendNotification
// val notificationManager = ContextCompat.getSystemService(
// app,
// NotificationManager::class.java
// ) as NotificationManager
// notificationManager.sendNotification(app.getString(R.string.eggs_ready), app)
- 再次运行应用。
- 设置计时器,让它在后台运行,然后等待该时间结束。您会看到一条通知。这是一条非常有用的通知。
第 4 步:添加内容 intent
- 再次运行应用(如果该应用尚未运行)。
- 点击此通知。毫无反应!
显示通知并告知用户这一操作很棒,但当用户点击通知时,他们会希望返回到相应的应用。在此 Codelab 的这一部分中,您将在通知中添加 intent,以便让用户返回到计时器屏幕。
Intent
是一个消息传递对象,可用于从其他应用组件请求操作。Intent 可用于启动 Activity、服务或传递广播。在这种情况下,您可以使用此 intent 在用户点按通知时告知系统打开 MainActivity
。由于您的应用仅包含一个视图,因此您在此处并没有太多选择。不过,在较大的应用中,通知应该为用户提供与通知交互时所需的屏幕,从而打造顺畅的体验。
- 打开
NotificationUtils.kt
并找到sendNotification()
扩展函数。 - 使用
applicationContext
和要启动的 activityMainActivity::class.java
创建一个Intent
。
// NotificationUtils.kt
fun NotificationManager.sendNotification(messageBody: String, applicationContext: Context) {
// Create the content intent for the notification, which launches
// this activity
// TODO: Step 1.11 create intent
val contentIntent = Intent(applicationContext, MainActivity::class.java)
您已创建 intent,但通知显示在应用外部。如需使 intent 在您的应用之外发挥作用,您需要创建一个新的 PendingIntent
。
PendingIntent
可授权其他应用或系统代表您的应用执行操作。PendingIntent
本身就是对系统维护的令牌的引用,该令牌描述了用于检索该令牌的原始数据。这意味着,即使自有进程被终止,PendingIntent
本身仍可用于分配给它的其他进程。在这种情况下,无论计时器应用是否正在运行,系统都会使用待处理 intent 代表您打开应用。
- 使用
applicationContext
、NOTIFICATION_ID
、您在上一步中创建的contentIntent
和PendingIntent
标志创建一个PendingIntent
。PendingIntent
标记指定创建新PendingIntent
或使用现有选项的选项。您需要将PendingIntent.FLAG_UPDATE_CURRENT
设置为标志,因为如果已有通知,则您不需要创建新通知。这样,您将修改与您提供的 intent 相关联的当前PendingIntent
。
// NotificationUtils.kt
// TODO: Step 1.12 create PendingIntent
val contentPendingIntent = PendingIntent.getActivity(
applicationContext,
NOTIFICATION_ID,
contentIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
- 将
PendingIntent
传递给通知。为此,您可以对NotificationBuilder
调用setContentIntent()
。现在,当您点击通知时,将触发PendingIntent
,从而打开您的MainActivity
。 - 此外,将
setAutoCancel()
设置为true
,这样当用户点按通知时,通知会在转到应用时自行关闭。
// NotificationUtils.kt
// TODO: Step 1.13 set content intent
.setContentIntent(contentPendingIntent)
.setAutoCancel(true)
- 再次运行应用。
- 设置计时器,将应用置于后台,然后等待通知显示。
- 看到通知后,只需下拉状态栏即可点击通知,然后观察应用如何转至前台。
第 5 步:取消通知
您的鸡蛋计时器运行正常且包含通知,但存在一个小问题。如果您设置了计时器,会收到通知,然后重新设置计时器,那么在新的计时器运行时,先前的通知会保留在状态栏中。如果应用在后台运行,可能会令用户感到困惑,并可能导致鸡蛋煮熟。
要解决此问题,您需要在启动新计时器时清除之前的通知。首先,在 NotificationUtils.kt
中创建另一个扩展函数。NotificationManager
具有用于取消所有有效通知(名为 cancelAll
()
)的 API。
- 打开
NotificationsUtil.kt
。 - 在
NotificationManager
上添加用于调用cancelAll()
的扩展函数。
// NotificationUtils.kt
// TODO: Step 1.14 Cancel all notifications
/**
* Cancels all notifications.
*
*/
fun NotificationManager.cancelNotifications() {
cancelAll()
}
- 打开
EggTimerViewModel.kt
并导航到startTimer()
函数。 - 在
startTimer()
内,从系统获取NotificationManager
的实例并调用cancelNotifications()
。
// EggTimerViewModel.kt
//TODO Step 1.15 call cancel notification
val notificationManager =
ContextCompat.getSystemService(
app,
NotificationManager::class.java
) as NotificationManager
notificationManager.cancelNotifications()
- 运行应用并启动计时器。
- 看到通知后,请再次启动计时器,并观察我们的应用如何从状态栏中自动删除之前的通知。
通知框架为开发者提供了各种自定义选项,以便他们设置自定义操作并根据需要设置通知样式。在此任务中,您将了解如何自定义鸡蛋计时器通知。
第 1 步:设置通知样式
根据需要设置通知的样式和通知内容会使通知脱颖而出,看起来更像是应用的扩展。通知框架提供了几种内置的样式供您使用,并且您可以随时创建自己的样式。
NotificationCompat
内置样式适用于:
BigTextStyle
:可以显示大量文本,例如在展开时显示电子邮件的内容。BigPictureStyle
,用于显示包含大型图片附件的大幅通知。InboxStyle
:用于显示对话样式文本内容。MediaStyle
,用于显示媒体播放的控件。MessagingStyle
:显示大幅通知,在任意人员之间发送多条消息。
如需详细了解其他样式,请参阅创建展开式通知文档。在此步骤中,您将使用 NotificationCompat.BigPictureStyle
创建一个展开式通知,在展开后显示一张大型的鸡蛋图片。
- 打开
NotificationUtils.kt
并找到sendNotification()
函数。 - 首先,使用
BitmapFactory
从resources
加载图片。
// NotificationUtils.kt
// TODO: Step 2.0 add style
val eggImage = BitmapFactory.decodeResource(
applicationContext.resources,
R.drawable.cooked_egg
)
- 创建一个新的
BigPictureStyle
并设置您的图片。 - 将
bigLargeIcon()
设置为null
,以便在展开通知时将大图标消失。
// NotificationUtils.kt
// TODO: Step 2.0 add style
val eggImage = BitmapFactory.decodeResource(
applicationContext.resources,
R.drawable.cooked_egg
)
val bigPicStyle = NotificationCompat.BigPictureStyle()
.bigPicture(eggImage)
.bigLargeIcon(null)
- 将
setStyle()
的样式设置为bigPicStyle
。 - 将具有
setLargeIcon()
的大图标设置为eggImage
,这样当通知收起时,图片将显示为较小的图标。
// NotificationUtils.kt
// TODO: Step 2.1 add style to builder
.setStyle(bigPicStyle)
.setLargeIcon(eggImage)
- 运行应用并设置计时器。首次显示通知时,它会在抽屉式通知栏中处于收起状态。如果您展开通知,系统会在扩展通知区域显示一张大图片。
第 2 步:通知操作
通知操作是您还可以添加到通知中的另一项自定义设置。目前,当用户点击通知时,您的通知会重定向到您的应用。除了此默认通知操作外,您还可以添加用于在通知中完成应用相关任务的操作按钮。
通知可以提供最多三个操作按钮,以便用户能够快速回复,例如暂停提醒或回复短信。这些操作按钮不应重复用户点按通知时执行的操作。
如需添加操作按钮,请将 PendingIntent
传递给构建器上的 addAction()
函数。这类似于通过调用 setContentIntent()
设置通知的默认点按操作,不同的是,您可以启动其他各种操作,例如,启动在后台执行作业的 BroadcastReceiver
,这样该操作就不会干扰已经打开的应用。
在此 Codelab 中,您已经获得了一个名为 SnoozeReceiver
的 BoadcastReceiver
。您将使用 SnoozeReceiver
来接收用户对通知操作的点击。在以下步骤中,您将添加代码,以便在用户点击延后操作按钮时将鸡蛋计时器通知延后 60 秒。点击“暂停”操作后,SnoozeReceiver
会收到 intent,并会在 60 秒后创建新的闹钟以发送新通知。
- 打开
SnoozeReceiver.kt
。此类类似于您之前使用的AlarmReceiver
。在以下步骤中,您将添加用于触发SnoozeReceiver
的onReceive()
函数的代码。简而言之,SnoozeReceiver
中的代码会创建一个新闹钟,并在一分钟后发送新通知。向下滚动到 onReceive 函数底部,从系统获取 notificationManager 的实例并调用 cancelAll。
// SnoozeReceiver.kt
val notificationManager = ContextCompat.getSystemService(
context,
NotificationManager::class.java
) as NotificationManager
notificationManager.cancelAll()
- 如需使用
SnoozeReceiver
,请打开NotificationUtils.kt
。 - 在
sendNotification()
函数中的样式后面,为SnoozeReceiver
创建一个新的Intent
snoozeIntent
。 - 对
PendingIntent
调用getBroadcast()
方法(该方法需要以下步骤中的参数),创建待定 intent。用户点按“延后”按钮 60 秒后,系统将使用此PendingIntent
设置新闹钟来发布新通知。 - 第一个参数是此
PendingIntent
应在其中启动 Activity 的应用上下文。 - 第二个参数是请求代码,即此待处理 intent 的请求代码。如果您需要更新或取消此待定 intent,则需要使用此代码访问待定 intent。
- 接下来,添加
snoozeIntent
对象,该对象是要启动的 activity 的 intent。 - 最后,添加
#FLAG_ONE_SHOT
的标志值,因为 intent 将仅使用一次。该快速操作和通知会在首次点按后消失,因此该 intent 只能使用一次。
// NotificationUtils.kt
// TODO: Step 2.2 add snooze action
val snoozeIntent = Intent(applicationContext, SnoozeReceiver::class.java)
val snoozePendingIntent: PendingIntent = PendingIntent.getBroadcast(
applicationContext,
REQUEST_CODE,
snoozeIntent,
FLAGS
)
- 接下来,对
notificationBuilder
调用addAction()
函数。此功能需要使用图标和文字来向用户描述您的操作。您还需要添加snoozeIntent
。当用户点击您的操作时,此 intent 将用于触发正确的boadcastReceiver
。
// NotificationUtils.kt
// TODO: Step 2.3 add snooze action
.addAction(
R.drawable.egg_icon,
applicationContext.getString(R.string.snooze),
snoozePendingIntent
)
- 运行鸡蛋计时器应用以测试延后操作。
- 运行计时器并将应用置于后台。计时器时间到时,展开通知,您会看到该通知现在有一个延后操作按钮,该按钮用于暂停鸡蛋计时器一分钟。
第 3 步:通知的重要性
重要性决定了通知在视觉和听觉上对用户的干扰程度。优先级较高的通知会给用户带来更多干扰。
您必须在 NotificationChannel
构造函数中指定重要性级别。您最初为鸡蛋计时器应用设置了低重要性。您可以从 IMPORTANCE_NONE(0)
到 IMPORTANCE_HIGH(4)
这 5 个重要级别中选择一个。您为渠道指定的重要性级别会应用到您在其中发布的所有通知消息。
渠道重要性级别
用户可见的重要性级别 | 重要性(Android 8.0 及更高版本) | 优先级(Android 7.1 及更低版本) |
发出声音并以浮动通知的形式显示(在屏幕顶部弹出) | ||
发出提示音 | ||
不发出提示音 | ||
不发出提示音,且不会在状态栏中显示 |
如需了解如何选择适当的优先级,请参阅通知设计指南中的“优先级”。在应用中为通知选择重要性级别时应格外小心,在选择渠道重要性时应考虑用户的时间和注意力。当不重要的通知伪装成紧急通知时,会生成不必要的警报并且会分散注意力。用户可以完全控制通知的重要程度,因此如果您创建了令人厌烦的通知,可能会彻底关闭通知渠道。
您在第 1.6 步中首次创建通知时,鸡蛋计时器设置为以较低的优先级发送通知,因为它设计为不会用通知来干扰用户。不过,最好在鸡蛋烹饪之前引起用户的注意。如需更改通知的重要程度,请从渠道设置开始。渠道重要性会影响在渠道中发布的所有通知的干扰级别,且必须在 NotificationChannel
构造函数中指定。
- 如需更改应用通知渠道的重要性级别,请打开
EggTimerFragment.kt
并导航至createChannel()
。将重要性级别从IMPORTANCE_LOW
更改为IMPORTANCE_HIGH
。
// EggTimerFragment.kt
val notificationChannel = NotificationChannel(
channelId,
channelName,
// TODO: Step 2.4 change importance
NotificationManager.IMPORTANCE_HIGH
)
为了支持搭载 Android 7.1(API 级别 25)或更低版本的设备,您还必须使用 NotificationCompat
类中的优先级常量针对每条通知调用 setPriority()
。
- 打开
NotificationUtils.kt
并将以下内容添加到通知构建器对象。
// NotificationUtils.kt
.addAction(
R.drawable.common_google_signin_btn_icon_dark,
applicationContext.getString(R.string.snooze),
snoozePendingIntent
)
// TODO: Step 2.5 set priority
.setPriority(NotificationCompat.PRIORITY_HIGH)
- 在运行该应用之前,请长按您的设备或模拟器上的应用图标,然后选择“卸载”以清除以前的频道设置。如果您未卸载该应用,则渠道优先级设置不会更改,并且这不会在通知发布时发生任何行为变化。
- 现在,再次运行应用并启动计时器。这一次,无论您的应用是在前台运行还是在后台运行,系统都会在屏幕顶部显示弹出式窗口。
第 4 步:通知标志
通知标志是当关联应用具有有效通知时,显示在关联应用的启动器图标上的小圆点。用户可以长按应用图标以显示通知。
这些称为“标记”的点默认显示,您的应用无需执行任何操作。不过,在某些情况下,标记对您的通知并没有任何意义,因此您可以通过对 NotificationChannel
对象调用 setShowBadge(false)
来按渠道停用标记。由于鸡蛋计时器在特定时间仅会显示一条有效通知,因此您的应用图标中的标志对用户没有多大帮助。在以下步骤中,您将停用徽章,并且仅显示鸡蛋计时器的通知。
- 为鸡蛋计时器的频道创建代码添加
setShowBadge(false)
以停用标志。
// EggTimerFragment.kt
).apply {
// TODO: Step 2.6 disable badges for this channel
setShowBadge(false)
}
- 再次运行应用,启动计时器并观察应用图标。您应该不会在应用图标上看到任何标记。
解决方案代码位于已下载代码的主分支中。
- 使用 NotificationManager 类创建、发送、更新和取消通知。
- 使用 NotificationChannel 对象通过 createNotificationChannel 方法设置通知的渠道。
- 使用 addAction() 向通知添加快速操作。
- 使用 setShowBadge() 启用或停用徽章。
- 使用从 Notification.Style 扩展的样式来设置通知样式
- 使用 NotificationChannel.setImportance() 设置重要性级别
Udacity 课程:
Android 开发者文档:
如需查看本课程中其他 Codelab 的链接,请参阅“使用 Kotlin 进行高级 Android 开发”的 Codelab 着陆页。