1page.title=通知 2page.tags=通知 3helpoutsWidget=true 4page.image=/preview/images/notifications-card.png 5 6trainingnavtop=true 7 8@jd:body 9 10<div id="qv-wrapper"> 11<div id="qv"> 12 13<!-- table of contents --> 14<h2>本文内容包括</h2> 15<ol> 16 <li><a href="#direct">直接回复</a></li> 17 <li><a href="#bundle">捆绑通知</a></li> 18 <li><a href="#custom">自定义视图</a></li> 19 <li><a href="#style">消息样式</a></li> 20</ol> 21 22</div> 23</div> 24 25<p>Android N 引入了一些新 API,允许应用发布具有高度可见性和交互性的通知。 26</p> 27 28<p>Android N 扩展了现有 {@link android.support.v4.app.RemoteInput} 通知 API,以支持手持式设备上的内联回复。 29此功能允许用户从通知栏快速进行回复,无需访问应用。 30</p> 31 32<p> 33 此外,Android N 还允许捆绑类似的通知并将它们显示为一则通知。 34为了实现此功能,Android N 使用现有的 {@link 35 android.support.v4.app.NotificationCompat.Builder#setGroup 36 NotificationCompat.Builder.setGroup()} 方法。用户可以从通知栏展开各通知,并分别对每则通知进行回复和清除等操作。 37 38 39</p> 40 41<p>最后,Android N 还添加了一些新 API,允许您在应用的自定义通知视图中使用系统装饰元素。 42这些 API 可帮助确保通知视图与标准模板的展示效果相一致。 43 44</p> 45 46<p>本文重点介绍您在应用中使用新通知功能时应加以考虑的一些重要变更。 47</p> 48 49<h2 id="direct">直接回复</h2> 50 51<p>利用 Android N 中的直接回复功能,用户可以直接在通知界面内快速回复短信或更新任务列表。 52 53在手持式设备上,可通过通知中另外附加的按钮进行内联回复操作。 54当用户通过键盘回复时,系统会将文本回复附加到您为通知操作指定的 Intent,并将 Intent 发送到手持式设备应用。 55 56 57 58 59 60<img id="fig-reply-button" src="{@docRoot}preview/images/inline-reply.png" srcset="{@docRoot}preview/images/inline-reply.png 1x, 61 {@docRoot}preview/images/inline-reply_2x.png 2x" width="400"> 62<p class="img-caption"> 63 <strong>图 1.</strong>Android N 添加了 <strong>Reply</strong> 操作按钮。 64 65</p> 66 67<h3>添加内联回复操作</h3> 68 69<p>要创建支持直接回复的通知操作: 70</p> 71 72<ol> 73<li>创建一个可添加到通知操作的 {@link android.support.v4.app.RemoteInput.Builder} 实例。 74 75该类的构造函数接受系统用作文本输入密钥的字符串。 76之后,手持式设备应用使用该密钥检索输入的文本。 77 78 79<pre> 80// Key for the string that's delivered in the action's intent. 81private static final String KEY_TEXT_REPLY = "key_text_reply"; 82String replyLabel = getResources().getString(R.string.reply_label); 83RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY) 84 .setLabel(replyLabel) 85 .build(); 86</pre> 87</li> 88<li>使用 <code>addRemoteInput()</code> 向操作附加 {@link android.support.v4.app.RemoteInput} 对象。 89 90 91<pre> 92// Create the reply action and add the remote input. 93Notification.Action action = 94 new Notification.Action.Builder(R.drawable.ic_reply_icon, 95 getString(R.string.label), replyPendingIntent) 96 .addRemoteInput(remoteInput) 97 .build(); 98</pre> 99</li> 100 101<li>对通知应用操作并发出通知。 102 103<pre> 104// Build the notification and add the action. 105Notification newMessageNotification = 106 new Notification.Builder(mContext) 107 .setSmallIcon(R.drawable.ic_message) 108 .setContentTitle(getString(R.string.title)) 109 .setContentText(getString(R.string.content)) 110 .addAction(action)) 111 .build(); 112 113// Issue the notification. 114NotificationManager notificationManager = 115 NotificationManager.from(mContext); 116notificationManager.notify(notificationId, newMessageNotification); 117 118</pre> 119</li> 120 121</ol> 122 123 124<p> 在触发通知操作时系统提示用户输入回复。 125 </p> 126 127<img id="fig-user-input" src="{@docRoot}preview/images/inline-type-reply.png" srcset="{@docRoot}preview/images/inline-type-reply.png 1x, 128 {@docRoot}preview/images/inline-type-reply_2x.png 2x" width="300"> 129<p class="img-caption"> 130 <strong>图 2.</strong>用户从通知栏输入文本。 131</p> 132 133<h3> 134 从内联回复检索用户输入 135</h3> 136 137<p> 138 要从通知界面接收用户输入并发送到在回复操作的 Intent 中声明的 Activity: 139 140</p> 141 142<ol> 143 <li>通过传递通知操作的 Intent 作为输入参数来调用 {@link android.support.v4.app.RemoteInput#getResultsFromIntent 144 getResultsFromIntent()}。 145该方法返回含有文本回复的 {@link android.os.Bundle}。 146 147 148 <pre> 149Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); 150</pre> 151 </li> 152 153 <li>使用产生的密钥查询捆绑包(提供给 {@link 154 android.support.v4.app.RemoteInput.Builder} 构造函数)。以下代码段说明了方法如何从捆绑包检索输入文本: 155 156 157 158 <pre> 159// Obtain the intent that started this activity by calling 160// Activity.getIntent() and pass it into this method to 161// get the associated string. 162 163private CharSequence getMessageText(Intent intent) { 164 Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); 165 if (remoteInput != null) { 166 return remoteInput.getCharSequence(KEY_TEXT_REPLY); 167 } 168 return null; 169 } 170</pre> 171 </li> 172 173 <li>使用您为上一项通知提供的相同的通知 ID 来建立和发布另一项通知。 174进度指示器从通知界面消失,以告知用户已回复成功。 175 176在处理这项新通知时,使用被传递到接收器 {@code onReceive()} 方法的上下文。 177 178 179 <pre> 180// Build a new notification, which informs the user that the system 181// handled their interaction with the previous notification. 182Notification repliedNotification = 183 new Notification.Builder(context) 184 .setSmallIcon(R.drawable.ic_message) 185 .setContentText(getString(R.string.replied)) 186 .build(); 187 188// Issue the new notification. 189NotificationManager notificationManager = 190 NotificationManager.from(context); 191notificationManager.notify(notificationId, repliedNotification); 192</pre> 193 </li> 194</ol> 195 196<p> 197 对于交互式应用(例如聊天),这可以用来在处理检索到的文本时添加其他上下文。 198例如,这些应用可以显示多行聊天记录。 199当用户通过 {@link 200 android.support.v4.app.RemoteInput} 回复时,您可以使用 {@code setRemoteInputHistory()} 方法更新回复历史。 201 202</p> 203 204<p> 205 在应用收到远程输入后,必须更新或取消通知。 206如果用户使用直接回复来对远程更新进行回复,则不可取消通知。 207 208否则,更新通知以显示用户的回复。对于使用 {@code MessagingStyle} 的通知,您应该添加回复来作为最新消息。 209 210当使用其它模板时,您可以将用户的回复追加到远程输入历史。 211 212</p> 213 214<h2 id="bundle">捆绑通知</h2> 215 216<p>Android N 为开发者提供了表示通知队列的新方法: 217 <i>捆绑通知</i>。这类似于 Android Wear 中的<a href="{@docRoot}training/wearables/notifications/stacks.html">通知堆栈</a>功能。 218 219例如,如果应用为接收的消息创建通知,那么在接收到多个消息时,应用会将通知捆绑在一起成为一个群组。 220 221您可以使用现有的 {@link android.support.v4.app.NotificationCompat.Builder#setGroup 222Builder.setGroup()} 方法捆绑类似的通知。 223</p> 224 225<p> 226 通知组对组内的通知施加层次结构。 227 层次结构的顶层是父级通知,其显示该群组的摘要信息。 228用户可以逐步展开通知组,随着用户深入展开,系统将显示更多信息。 229 230当用户展开捆绑包时,系统将显示其所有子通知的更多信息;当用户展开其中一则通知时,系统显示该通知的所有内容。 231 232 233</p> 234 235<img id="fig-bundles" src="{@docRoot}preview/images/bundles.png" srcset="{@docRoot}preview/images/bundles.png 1x, 236 {@docRoot}preview/images/bundles_2x.png 2x" width="300"> 237<p class="img-caption"> 238 <strong>图 3.</strong>用户可以逐步展开通知组。 239 240</p> 241 242<p class="note"> 243 <strong>注:</strong>如果同一应用发送了四条或以上通知,并且未指定分组,系统会自动将它们分到一组。 244 245 246</p> 247 248<p>如需了解如何将通知添加到组,请参阅<a href="{@docRoot}training/wearables/notifications/stacks.html#AddGroup">将各通知添加到组</a>。 249 250</p> 251 252 253<h3 id="best-practices">捆绑通知最佳做法</h3> 254<p>本节提供了有关何时使用通知组而非早期版本 Android 平台中的 {@link android.app.Notification.InboxStyle InboxStyle} 通知的指南。 255 256 257</p> 258 259<h3>何时使用捆绑通知</h3> 260 261<p>只有在您的用例满足以下所有条件时才应使用通知组: 262</p> 263 264<ul> 265 <li>子通知为完整通知,且可以单独显示,无需群组摘要。 266</li> 267 <li>单独显示子通知更合理。例如: 268 269 </li> 270 <ul> 271 <li>子通知可操作,且每个子通知均有特定的操作。</li> 272 <li>子通知中包含用户想要查看的更多信息。</li> 273 </ul> 274</ul> 275 276<p>好的通知组用例示例包括:显示传入消息列表的短信应用,或显示收到的电子邮件列表的电子邮件应用。 277 278</p> 279 280<p> 281适合显示单一通知的用例示例包括:从某一个人收到的单独消息,或以列表表示的单行文本项目。 282 283您可以使用 {@link android.app.Notification.InboxStyle InboxStyle} 或 284{@link android.app.Notification.BigTextStyle BigTextStyle} 实现此功能。 285 286 287</p> 288 289<h3 id ="post">显示捆绑通知</h3> 290 291<p> 292 即使组内仅含有一则子通知,应用也应发布组摘要。 293如果只含有一则通知,系统将取消摘要并直接显示子通知。 294这样可确保用户在滑动切换组内的子通知时,系统仍可以提供一致的用户体验。 295 296 297</p> 298 299<p class="note"> 300 <strong>注:</strong>本版本 Android N 目前还无法在仅含一则子通知时取消通知组的摘要。 301我们将在之后版本的 Android N 中添加此功能。 302 303</p> 304 305<h3>扫视通知</h3> 306 307<p>虽然系统通常以群组的方式显示子通知,但您可以进行设置,使其暂时作为<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#Heads-up">浮动通知</a>显示。 308 309 310该功能非常实用,因为其允许用户立即访问最近的子通知以及与其相关的操作。 311 312</p> 313 314 315<h3>后向兼容性</h3> 316 317<p> 318 自 Android 5.0(API 级别 21)起,{@link 319 android.app.Notification} API 中就添加了通知组和远程输入,以支持 Android Wear 设备。 320如果您已经使用这些 API 构建通知,则只需验证应用行为是否符合上述指南,并考虑实现 {@code 321 setRemoteInputHistory()}。 322 323 324</p> 325 326<p> 327 为了支持后向兼容性,支持库的 {@link android.support.v4.app.NotificationCompat} 类中提供了相同的 API,以便您构建可在早期 Android 版本中运行的通知。 328 329 330在手持式设备和平板电脑上,用户只能看到摘要通知,因此应用应仍提供收件箱式或类似形式的通知显示模式,以显示群组的全部信息内容。 331 332鉴于 Android Wear 设备允许用户查看所有子通知,包括更早级别平台上的通知,您应在不依赖 API 级别的基础上构建子通知。 333 334 335 336</p> 337 338<h2 id="custom"> 自定义视图</h2> 339<p>从 Android N 开始,您将可以自定义通知视图,同时仍可以使用系统装饰元素,例如通知标头、操作和可展开的布局。 340 341</p> 342 343<p>为启用该功能,Android N 添加了以下 API,以便您样式化自己的自定义视图: 344</p> 345 346<dl> 347<dt> 348{@code DecoratedCustomViewStyle()}</dt> 349<dd> 样式化除媒体通知外的其他通知。 350</dd> 351<dt> 352{@code DecoratedMediaCustomViewStyle()}</dt> 353<dd> 样式化媒体通知。</dd> 354</dl> 355 356<p>如需使用这些新 API,可调用 {@code setStyle()} 方法,并向其传递所需的自定义视图样式。 357</p> 358 359<p>此代码段显示了如何使用 {@code DecoratedCustomViewStyle()} 方法构建自定义通知对象。 360</p> 361 362<pre> 363Notification notification = new Notification.Builder() 364 .setSmallIcon(R.drawable.ic_stat_player) 365 .setLargeIcon(albumArtBitmap)) 366 .setCustomContentView(contentView); 367 .setStyle(new Notification.DecoratedCustomViewStyle()) 368 .build(); 369 370</pre> 371 372<h2 id="style">消息传递样式</h2> 373<p> 374 Android N 引入了一项新的 API 来自定义通知样式。 375 使用 <code>MessageStyle</code> 类,您可以更改在通知中显示的多个标签,包括会话标题、其他消息和通知的内容视图。 376 377 378</p> 379 380<p> 381 以下代码段演示了如何使用 <code>MessageStyle</code> 类来自定义通知样式。 382 383</p> 384 385<pre> 386 Notification notification = new Notification.Builder() 387 .setStyle(new Notification.MessagingStyle("Me") 388 .setConversationTitle("Team lunch") 389 .addMessage("Hi", timestamp1, null) // Pass in null for user. 390 .addMessage("What's up?", timestamp2, "Coworker") 391 .addMessage("Not much", timestamp3, null) 392 .addMessage("How about lunch?", timestamp4, "Coworker")); 393</pre> 394