在此 Codelab 中,您将学习如何在通知栏的“对话”部分中显示通知,以及如何将这些通知显示为“对话泡”。
对话是指两个或更多用户之间的双向实时通信。这些对话会在系统通知栏中的专用区域内显示。此外,它们还可以升级为对话泡。对话泡是一种圆形图标,它们浮动在其他应用内容上层,并会跟随用户转到任意位置。对话泡适合用于显示用户希望随时能够轻松访问的持续性活动和操作。
对话泡是向用户持续通报重要信息的绝佳方式。不过,您应该注意使用对话泡的时机。对话泡会占用屏幕空间并遮盖其他应用内容。请仅在迫切需要吸引用户注意力时使用对话泡。请注意,用户可以轻松地选择停用对话泡,并改用常规通知。
此 Codelab 使用一个概念验证聊天应用作为起点。此应用会显示新收到的消息,对于此 Codelab,我们将假定用户希望在一段时间内留意这些消息。
| 对话泡 |
学习内容
- 如何显示对话通知。
- 如何支持对话泡。
- 当应用在前台运行时,如何显示对话泡。
前提条件
- Kotlin 基础知识(此 Codelab 采用 Kotlin)
- 关于通知的基础知识。如需详细了解通知,请点击此处,或参阅“使用 Android 通知”Codelab。
- 搭载 Android 11 Beta 版 1 或更高版本的设备或模拟器。
- Android Studio 4.0.0 或更高版本。
下载 Codelab 代码:
$ git clone https://github.com/googlecodelabs/android-people.git
在 Android Studio 中导入项目。
Gradle 将开始同步。这可能需要几分钟的时间,具体取决于互联网连接速度以及您近期打开的其他项目。
该项目包含多个模块:
app-start
是此 Codelab 的起始状态。app
是完成此 Codelab 后应用的最终状态。
请确保组合框中的 app-start
已针对相应运行配置选中。
我们要处理的是一款聊天应用。请在 Android Studio 中运行此应用,此时,您会看到可与之聊天的聊天联系人列表。
请选择一位联系人,然后尝试发送消息。您将在 5 秒内收到回复。如果聊天屏幕不在前台,相应回复就会显示为通知。请尝试发送消息,然后快速转到主屏幕。
现在,您已经了解此应用的工作原理了,接下来,让我们先在通知栏的“对话”部分中显示我们的通知。
通知必须符合以下条件,才能让系统将其视为对话:
- 它使用
MessagingStyle
。 - 它与某个对话快捷方式相关联。对话快捷方式是一种共享快捷方式,可用作直接共享目标,并会长期存在。
MessagingStyle
- 打开
NotificationHelper.kt
。此文件位于data/NotificationHelper.kt
。此应用的所有通知都会显示在showNotification
方法中。通知目前使用对setContentText
的简单调用来设置通知内容。请找到 TODO 1 并将其替换为 MessagingStyle。
.setStyle( Notification.MessagingStyle(user) .apply { val lastId = chat.messages.last().id for (message in chat.messages) { val m = Notification.MessagingStyle.Message( message.text, message.timestamp, if (message.isIncoming) person else null ).apply { if (message.photoUri != null) { setData(message.photoMimeType, message.photoUri) } } if (message.id < lastId) { addHistoricMessage(m) } else { addMessage(m) } } } .setGroupConversation(false) ) .setWhen(chat.messages.last().timestamp)
对话快捷方式
- 同一
NotificationHelper.kt
中有一个名为updateShortcuts
的方法。每次显示新通知时,系统都会调用此方法。我们将创建动态快捷方式,并将其注册到ShortcutManager
。请找到 TODO 2 并添加此实现。
var shortcuts = Contact.CONTACTS.map { contact -> val icon = Icon.createWithAdaptiveBitmap( context.resources.assets.open(contact.icon).use { input -> BitmapFactory.decodeStream(input) } ) ShortcutInfo.Builder(context, contact.shortcutId) .setLocusId(LocusId(contact.shortcutId)) .setActivity(ComponentName(context, MainActivity::class.java)) .setShortLabel(contact.name) .setIcon(icon) .setLongLived(true) .setCategories(setOf("com.example.android.bubbles.category.TEXT_SHARE_TARGET")) .setIntent( Intent(context, MainActivity::class.java) .setAction(Intent.ACTION_VIEW) .setData( Uri.parse( "https://android.example.com/chat/${contact.id}" ) ) ) .setPerson( Person.Builder() .setName(contact.name) .setIcon(icon) .build() ) .build() } if (importantContact != null) { shortcuts = shortcuts.sortedByDescending { it.id == importantContact.shortcutId } } val maxCount = shortcutManager.maxShortcutCountPerActivity if (shortcuts.size > maxCount) { shortcuts = shortcuts.take(maxCount) } shortcutManager.addDynamicShortcuts(shortcuts)
在此实现中,我们要将所有联系人转换为 ShortcutInfo
,并通过最终调用 addDynamicShortcuts
将它们设置为动态快捷方式。
这些快捷方式的类别为“com.example.android.bubbles.category.TEXT_SHARE_TARGET
”。此类别在 res/xml/shortcuts.xml
中定义,并可用作直接共享目标。
- 如果您查看
MainActivity.kt
,您会发现它已能针对我们的联系人处理ACTION_SEND
intent。我们想要指定,此 activity 应处理来自“直接共享”的 intent。请在AndroidManifest.xml
中找到 TODO 3,并在 MainActivity 中添加以下元素。此操作会将该 activity 与上面创建的动态快捷方式相关联。
<activity android:name="com.example.android.people.MainActivity" ...> <!-- ... --> <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts" /> </activity>
- 本部分的最后一步是将通知与我们刚刚创建的动态快捷方式相关联。请在
NotificationHelper.kt
中找到 TODO 4,并将以下配置添加到Notification.Builder
。
// ... .setCategory(Notification.CATEGORY_MESSAGE) .setShortcutId(chat.contact.shortcutId) .setLocusId(LocusId(chat.contact.shortcutId))
借助此 setShortcutId
,系统可以确定相应通知与指定的动态快捷方式相对应。此外,我们还建议您设置 LocusId
,以便系统根据应用的使用情况对对话进行准确排名。
动态快捷方式 | 对话通知 |
通知必须发送到通知渠道。此应用使用一个通知渠道。请注意,重要性已在 setUpNotificationChannels
方法中设为 IMPORTANCE_HIGH
。若要将通知显示为对话泡,通知渠道必须设为
IMPORTANCE_HIGH
。
可以通过向通知添加 BubbleMetadata
来将其显示为对话泡。只需调用 Notification.Builder#setBubbleMetadata
即可实现这一点。
- 请将
showNotification
方法中的 TODO 5 替换为以下代码:
NotificationHelper.kt
> showNotification()
.setBubbleMetadata(
Notification.BubbleMetadata
.Builder(
PendingIntent.getActivity(
context,
REQUEST_BUBBLE,
Intent(context, BubbleActivity::class.java)
.setAction(Intent.ACTION_VIEW)
.setData(contentUri),
PendingIntent.FLAG_UPDATE_CURRENT
),
icon
)
.setDesiredHeightResId(R.dimen.bubble_height)
.build()
)
在以上代码中,setIcon
会设置对话泡的图标。
setIntent
可指定要作为“展开的对话泡”启动的 Activity。如果用户点按对话泡,展开的对话泡就会打开,并在当前屏幕上层显示相应的聊天记录。我们将 BubbleActivity
用作展开的对话泡。若要将 Activity 用作展开的对话泡,必须在清单文件中为其配置一些属性。
- 请打开 AndroidManifest.xml 并找到标有 TODO 6 的
BubbleActivity
的定义。将以下属性添加到此元素:
AndroidManifest.xml
> BubbleActivity
<activity
android:name="com.example.android.people.BubbleActivity"
android:allowEmbedded="true"
android:documentLaunchMode="always"
android:resizeableActivity="true">
...
</activity>
以下 3 个属性是必需的:
allowEmbedded="true"
- 展开对话泡会嵌入系统界面中。resizeableActivity="true"
- 展开的对话泡会由系统界面调整大小。documentLaunchMode="always"
- 系统界面需要此属性,以便为此 Activity 创建多个实例。
- 现在,从 Android Studio 运行此应用。向某位联系人发送消息,然后快速关闭此应用。现在,您应该会在右下角看到带有对话泡图标的通知。
带对话泡图标的通知
点按“对话泡”图标后,您应该能够看到通知以对话泡形式显示。点按一次该图标后,系统会自动将来自同一联系人的通知显示为对话泡。点按此对话泡后,它应该会显示展开的对话泡。
对话泡 | 展开的对话泡 |
有时,应用在前台时也可能需要显示对话泡。在此应用中,我们希望以对话泡的形式“弹出”一个聊天屏幕,让用户能够将暂时需要留意的聊天置顶。我们已在聊天屏幕上添加了用于实现此操作的菜单按钮。
重新打开 NotificationHelper.kt
。点按此菜单按钮可调用 showNotification
方法,并将参数 fromUser
设为 true。此时,我们需要将此通知显示为前台对话泡。
将以下代码行添加到我们在上一部分中添加的 BubbleMetadata 中:
NotificationHelper.kt
> showNotification()
Notification.BubbleMetadata // ... .setDesiredHeightResId(R.dimen.bubble_height) .apply { if (fromUser) { setAutoExpandBubble(true) setSuppressNotification(true) } } .build()
setAutoExpandBubble
会让系统在默认情况下将对话泡显示为展开状态。此外,我们还想通过调用 setSuppressNotification
来禁止显示初始通知。只有当您的应用在前台运行时,这些标记才有效。
恭喜!现在,您已了解如何显示对话通知和对话泡。