第7章 通知

一个通知是一条消息他是显示于你应用程序之外的一个界面中。当你告诉系统要发布一个通知时,它首先作为一个icon出现在通知区域。为了看见通知的细节,用户可以点击通知区域展开一个新的界面。下面让我们来看一下图7-1和图7-2:

图7-1 通知出现在通知区域

图7-2 通知展开后的效果(drawer)

注意:除非特别注明外,本章指的都是NotificationCompat.Builder,它在v4 Support Library中有,正式添加于API Level 15。但有了v4 Support Library低版本系统也能用。另外Notification.Builder添加于android3.0。

7.1 通知显示元素

通知有两种可视化风格,它取决于版本和drawer的状态:

标准view

在drawer中标准的通知view

大型view

一个比较大的view。这个view是通知扩展的一个部分,这个功能被添加于android 4.1。

7.1.1正常view

一个标准view一般高位64dp。即使你创建一个大的view风格,直到它展开之前他仍然出现在标准view中。如图7-3:

图7-3 在标准view下的通知

以下是每个部分的说明:

1. 内容标题

2. 大型icon

3. 内容text

4. 内容info

5. 小型icon

6. 发布通知的时间。你能使用setWhen()设置一个明确的值。

7.1.2大型view

当通知被展开时,大型view才会出现并显示,一般由用户使用展开手势,通知drawer会被展开。展开的通知在android 4.1上才可用。如图7-4所示:

图7-4 在大型view下的通知

注意大型View大部分的视觉元素与正常的视图共享。仅仅不同的地方是编号为数字7的地方,这个细节区域。各大View风格设置有些不同。可用的风格有:

Big picture style

细节区域包含一个256dp高度的bitmap在它的细节部分。

Big text style

在细节部分显示一个大型文本块。

Inbox style

在细节部分显示文本行数。

下面是大型view可用,但标准view不可用的风格:

Big content title

允许你覆盖标准view的内容标题,使之出现在展开view中

Summary text

允许你在细节区域添加文本行数。

7.2 创建一个通知

你想在NotificationCompat.Builder对象中为通知指定UI信息和动作,就必须先使用NotificationCompat.Builder.build()来创建通知,这个方法会返回一个Notification对象,为了发布通知,你可以通过调用NotificationManager.notify()来传递Notification对象到系统中。

7.2.1必须的通知内容

一个Notification对象必须包含以下内容:

通过setSmallIcon()设置一个小的icon

通过setContentTitle()来设置一个标题

通过setContentText()来设置细节文本

7.2.2可选的通知的内容和设置

所有其他通知设置和内容都是可选的,具体可参考API NotificationCompat.Builder类

7.2.3通知动作(action)

虽然它们是可选的,你应该至少添加一个动作到你的通知中。一个动作允许用户直接从通知到一个你应用程序的Activity中。一个通知能提供多个动作。你应该总是定义一个动作,当用户点击通知时,触发它。通常这个动作打开一个你应用程序中的Activity。你也能添加按钮到通知中(Android 4.1中加入的新功能),用来执行额外的动作,如一个警告或即时响应的文本消息。如果你使用附加的动作按钮,你必须让他们的功能在一个Activity中可用。在通知里面,这个动作通过PendingIntent来定义,请使用NotificationCompat.Builder中合适的方法来创建。例如,当用户在Drawer中点击通知文本的时候,你想要启动Activity,你就可以通过调用setContentIntent()来添加一个PendingIntent。用户点击通知启动一个Activity是最常见的情况。请记住在Androird4.1或更高版本中,你才能从一个动作按钮中启动一个Activity。

7.2.4 创建一个简单的通知

以下代码片段是一个简单的例子,当一个用户点击通知时会打开一个activity。注意此段代码创建一个TaskStackBuilder对象并使用它创建一个PendingIntent。如代码清单7-1所示:

  1. NotificationCompat.Builder mBuilder =
  2. new NotificationCompat.Builder(this)
  3. .setSmallIcon(R.drawable.notification_icon)
  4. .setContentTitle("My notification")
  5. .setContentText("Hello World!");
  6. Intent resultIntent = new Intent(this, ResultActivity.class);
  7.  
  8. TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
  9. stackBuilder.addParentStack(ResultActivity.class);
  10. stackBuilder.addNextIntent(resultIntent);
  11. PendingIntent resultPendingIntent =
  12. stackBuilder.getPendingIntent(
  13. 0,
  14. PendingIntent.FLAG_UPDATE_CURRENT
  15. );
  16. mBuilder.setContentIntent(resultPendingIntent);
  17. NotificationManager mNotificationManager =
  18. (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
  19. mNotificationManager.notify(mId, mBuilder.build());

代码清单 7-1

7.2.5 应用一个大型的view风格到通知中

当一个通+知展开后出现一个大型的view,首先创建一个你想要的NotificationCompat.Builder对象。然后调用Builder.setStyle()传入大型view的风格对象。记住android4.1之前的版本是不可用的。当然后面我们会讲解如何兼容低版本。下面代码清单7-2是在7-1上做了适当修改:

  1. NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
  2. .setSmallIcon(R.drawable.notification_icon)
  3. .setContentTitle("Event tracker")
  4. .setContentText("Events received")
  5. NotificationCompat.InboxStyle inboxStyle =
  6. new NotificationCompat.InboxStyle();
  7. String[] events = new String[6];
  8. inboxStyle.SetBigContentTitle("Event tracker details:");
  9. ...
  10. for (int i=0; i < events.length; i++) {
  11.  
  12. inboxStyle.addLine(events[i]);
  13. }
  14. mBuilder.setStyle(inBoxStyle);
  15. ...

代码清单 7-2

7.2.6 处理兼容性

并不是所有通知功能都用于特别的版本。例如动作按钮,依赖于展开的通知,它只出现于android 4.1和高版本中。因为只有在这个版本上展开的通知才可用。为了确保最好的兼容性,请使用NotificationCompat及其子类创建通知,最好是用NotificationCompat.Builder,此外当你实现一个通知,请遵循以下过程:

1. 不管用户使用什么系统版本,都应该提供通知所有的功能给所有用户,为了做到这一点,需要在一个activity中验证所有的功能可用。你可能想要添加一个新的Activity。例如,如果您想要使用addAction()来控制停止和启动媒体播放,首先需要在一个Activity中实现这个控制。

2. 当用户点击通知时,确保所有用户点击后都能启动一个界面。我们需要为Activity创建一个PendingIntent。然后使用setContentIntent()把PendingIntent添加到通知中。

7.3 管理通知

当你需要为同一类型的事件多次处理一个通知时,你应该避免每次重新生成新的通知。你应该考虑更新先前的通知,不是改变一些值就是添加一些值。例如,Gmail通知用户新的email已经收到了,并且未读消息会自增计数,其实就是没收到一个通知消息做了处理。这就是所谓的“堆叠”通知。

7.3.1 更新通知

通知当然是可以被更新,使用通知ID来更新它,调用NotificationManager.notify(ID, notification)即可。如果先前的通知仍然可见,系统会从Notification 对象的content中更新它。如果先前的通知已经dismiss掉了,一个新的通知将被创建。下面的代码演示了一个通知更新并显示事件数量,如代码清单7-3所示:

  1. mNotificationManager =
  2. (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
  3. //被更新的通知ID
  4. int notifyID = 1;
  5. mNotifyBuilder = new NotificationCompat.Builder(this)
  6. .setContentTitle("New Message")
  7. .setContentText("You've received new messages.")
  8. .setSmallIcon(R.drawable.ic_notify_status)
  9. numMessages = 0;
  10. ...
  11. mNotifyBuilder.setContentText(currentText)
  12. .setNumber(++numMessages);
  13. // 因为ID保持不变,存在的通知被更新
  14. mNotificationManager.notify(
  15. notifyID,
  16. mNotifyBuilder.build());
  17. ...

代码清单 7-3

上面那些代码运行后就会生成如图7-5所示的效果:

图7-5 在drawer中显示更新通知

7.3.2 移除通知

移除通知的方法如下:

1. 用户通过个人或“Clear All” dismiss通知

2. 用户点击通知并且你在创建通知的时候调用了setAutoCancel()方法

3. 你根据指定的通知ID调用cancel()方法。这个方法也删除正在进行中的通知

4. 你调用cancelAll(),它将删除你先前所有的通知

7.4 当启动一个Activity时保持导航

当你从一个通知中启动一个Activity的时候,你必须保存用户的语气导航体验。点击返回键将和点击Home键的效果一样。为了保存导航的用户体验,你应该在一个新的任务中启动Activity。根据给定的新任务如何设置PendingIntent取决于你启动的Activity的性质。通常有两种情况:

1. 常规activity

正常启动Activity的情况下,设置PendingIntent来启动一个新的任务,并给PendingIntent提供一个后台堆栈,以复制应用程序正常点击Back键的行为。从Gmail APP中来演示这个通知。当出现一条信息时你点击通知,就会看到信息本身。当你点击Back键时你会通过Gmail回退到Home屏幕,就像你已经进入了Gmail,从Gmail退到Home屏幕一样。

2. 特别的activity

这种Activity,是在某种意义上Activity扩展了通知提供的信息,因为很难显示在通知本身。在这种情况下,设置PendingIntent启动一个新的任务。没有必要创建一个后台堆栈,因为这个Activity并不是属于应用程序正常流程下的一部分。点击Back键后依然会显示Home屏幕。

7.4.1 通过PendingIntent设立一个规则的activity

1. 在manifest中定义你应用程序的Activity层级。

◆支持Android 4.0.3和更早期的版本。在<activity>节点下添加子节点<meta-data>。表示父Activity与子Activity的关系。在<meta-data>节点下设置

android:name="android.support.PARENT_ACTIVITY"

android:value="<parent_activity_name>"

◆支持Android4.1和更高的版本。在<activity>节点中添加android:parentActivityName属性

完美支持的xml代码如代码清单7-4所示:

  1. <activity
  2.  
  3. android:name=".MainActivity"
  4.  
  5. android:label="@string/app_name" >
  6.  
  7. <intent-filter>
  8.  
  9. <action android:name="android.intent.action.MAIN" />
  10.  
  11. <category android:name="android.intent.category.LAUNCHER" />
  12.  
  13. </intent-filter>
  14.  
  15. </activity>
  16.  
  17. <activity
  18.  
  19. android:name=".ResultActivity"
  20.  
  21. <!—android 4.1和更高版本 -->
  22.  
  23. android:parentActivityName=".MainActivity">
  24.  
  25. <!—android 4.0.3和更早版本 -->
  26.  
  27. <meta-data
  28.  
  29. android:name="android.support.PARENT_ACTIVITY"
  30.  
  31. android:value=".MainActivity"/>
  32.  
  33. </activity>

代码清单 7-4

2. 创建一个后台推栈基于Intent启动的Activity:

◆创建Intent来启动Activity

◆通过调用TaskStackBuilder.create()来创建一个任务栈

◆通过调用addParentStack()把后台推栈添加到栈中。对于你在manifest中定义的每一个Activity层级,后台堆栈都包含一个启动Activity的Intent对象。并且这个方法还添加了标记(flag)来启动新任务中的堆栈。注意:尽管addParentStack()的参数是一个启动Activity的引用,但这个方法实际并没有添加Intent进去。

◆通过调用addNextIntent()来添加Intent对象。它添加的对象就是最上面◆创建的那个intent对象。

◆如果你需要在堆栈上添加参数到Intent对象你可以调用TaskStackBuilder.editIntentAt()。这有时候是必要的, 当用户使用back键导航回来,以确保目标Activity显示有意义的数据。

◆调用getPendingIntent()获得一个PendingIntent。然后你能调用setContentIntent()把这个PendingIntent作为参数。

下面的代码片段演示了这个过程,如代码清单7-5所示:

  1. ...
  2. Intent resultIntent = new Intent(this, ResultActivity.class);
  3. TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
  4. // 添加后台堆栈
  5. stackBuilder.addParentStack(ResultActivity.class);
  6. // 添加Intent到栈顶
  7. stackBuilder.addNextIntent(resultIntent);
  8. // 获得一个PendingIntent包含整个后台堆栈 containing the entire back stack
  9. PendingIntent resultPendingIntent =
  10. stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
  11. ...
  12. NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
  13. builder.setContentIntent(resultPendingIntent);
  14. NotificationManager mNotificationManager =
  15. (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
  16. mNotificationManager.notify(id, builder.build());

代码清单 7-5

7.4.2 通过PendingIntent设立一个专用的activity

以下部分描述了怎样通过PendingIntent设置一个专用的activity。

一个专用的Activity 不需要后台栈,因此你不一定要在manifest中定义它的Activity层级,并且你不必调用addParentStack() 来构建一个后台栈。反而使用manifest设置Activity的任务选项,并通过调用getActivity()创建PendingIntent:

1. 在manifest中添加以下属性到<activity>节点中。

◆android:name="activityclass"

完整的类名

◆android:taskAffinity=""

于代码中设置的FLAG_ACTIVITY_NEW_TASK 标记相结合,它确保这个activity不能进入应用程序的默认任务中。

◆android:excludeFromRecents="true"

从Recents排除了新的任务,以便用户不会意外导航回它。

如代码清单7-6所示:

  1. <activity
  2. android:name=".ResultActivity"
  3. ...
  4. android:launchMode="singleTask"
  5. android:taskAffinity=""
  6. android:excludeFromRecents="true">
  7. </activity>
  8. ...

代码清单 7-6

2. 构建和发布通知

◆创建一个Intent来启动Activity

◆设置Activity启动在一个新的、空的任务中,通过setFlags()方法来处理,传入FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TASK

◆为Intent设置其他需要的选项

◆通过getActivity()从Intent中创建一个PendingIntent。你能使用这个PendingIntent对象,把他作为参数传到setContentIntent()中

如代码清单7-7所示:

  1. NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
  2. Intent notifyIntent =
  3. new Intent(new ComponentName(this, ResultActivity.class));
  4. notifyIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
  5. PendingIntent notifyIntent =
  6. PendingIntent.getActivity(
  7. this,
  8. 0,
  9. notifyIntent
  10. PendingIntent.FLAG_UPDATE_CURRENT
  11. );
  12.  
  13. builder.setContentIntent(notifyIntent);
  14. NotificationManager mNotificationManager =
  15. (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
  16. mNotificationManager.notify(id, builder.build());

代码清单 7-7

7.5 显示通知的进度

通知可以包括一个动画进度指示器显示用户正在运行的操作的状态。如果你能估计这种操作需要花费多长时间,可以使用"determinate"形式的指示器(一个progress bar)。如果你不能估计花费的时间,使用“indeterminate”形式的指示器。

7.5.1 显示一个固定的时间进度指示器

显示一个确定的进度条, 通过调用setProgress()添加bar到你的通知中,setProgress(max, progress, false),然后发出通知。如代码清单7-8所示:

  1. ...
  2. mNotifyManager =
  3. (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
  4. mBuilder = new NotificationCompat.Builder(this);
  5. mBuilder.setContentTitle("Picture Download")
  6. .setContentText("Download in progress")
  7. .setSmallIcon(R.drawable.ic_notification);
  8. new Thread(
  9. new Runnable() {
  10. @Override
  11. public void run() {
  12. int incr;
  13.  
  14. for (incr = 0; incr <= 100; incr+=5) {
  15.  
  16. mBuilder.setProgress(100, incr, false);
  17.  
  18. mNotifyManager.notify(0, mBuilder.build());
  19.  
  20. try {
  21. Thread.sleep(5*1000);
  22. } catch (InterruptedException e) {
  23. Log.d(TAG, "sleep failure");
  24. }
  25. }
  26.  
  27. mBuilder.setContentText("Download complete")
  28.  
  29. .setProgress(0,0,false);
  30. mNotifyManager.notify(ID, mBuilder.build());
  31. }
  32. }
  33. ).start();

代码清单 7-8

图7-6则是运行后的效果

图7-6 通知中progress bar运行的效果

7.5.2显示一个持续的Activity指示器

为了显示不确定的activity指示器,使用setProgress(0, 0, true)添加它到你的通知中,前面两个参数可以忽略,然后发出通知。它的结果是一个指示器,具有和进度条相同的样式,不同的地方就是它的动画是持续的。在操作开始的地方就发出通知,这个动画将一直执行,直到你修改通知为止。将操作完成时,你应该手动调用setProgress(0, 0, false)然后更新通知移除activity指示器。如果你不这么做就算操作完成动画也会继续运行。下面让我们看下代码清单7-9:

  1. mBuilder.setProgress(100, incr, false);
  2. mNotifyManager.notify(0, mBuilder.build());

代码清单 7-9

运行后的效果如图7-7所示:

图7-7 持续的activity指示器动画

7.6 自定义通知布局

通知框架允许你自定义通知布局,它在一个RemoteViews 对象中定义了通知的外观。自定义布局通知和正常的通知类似,它们都是基于一个RemoteViews定义在一个XML布局文件。自定义通知的可用高度取决于通知view的布局。正常view布局限制为64dp,展开view布局限制为256dp。自定义通知布局,通过实例化一个RemoteViews对象然后inflates一个xml布局文件启动。不再调用setContentTitle()方法,而使用setContent()方法来设置自定义通知的内容细节。使用这个方法在RemoteViews中来设置view子类的值:

1. 为通知创建一个单独的xml布局文件。

2. 在你的应用程序中,使用RemoteViews方法来定义你通知的icon和文本。调用setContent()方法put这个RemoteViews对象到你的NotificationCompat.Builder中。避免正在RemoteViews对象中设置Drawable背景,因为你的文本颜色可能会变的看不清。

RemoteViews类也包括早期Chronometer或ProgressBar中的方法 ,更多详细信息请参考API文档。

当你使用自定义通知布局时,请特别注意不同的设备分辨率和水平方向上的问题。不要让你的自定义布局太复杂,一定要在各种配置中测试。

本文来自jy02432443,是本人辛辛苦苦一个个字码出来的,转载请保留出处,并保留追究法律责任的权利 QQ78117253 

第三部分:Android 应用程序接口指南---第二节:UI---第七章 通知的更多相关文章

  1. 第三部分:Android 应用程序接口指南---第二节:UI---第一章 用户界面和布局

    第1章 用户界面和布局 应用程序的用户界面就是用户能看到并可以与它交互的任何东西.Android提供多种预置的UI组件,如结构化布局对象和允许你为应用程序创建图形用户界面的UI控件.Android也会 ...

  2. 第三部分:Android 应用程序接口指南---第二节:UI---第二章 输入控件

    第2章 输入控件 输入控件是应用程序中用户接口的一种交互式组件.Android提供了大量的可供人们在UI中使用的控件,比如按钮.文本区域.(带滑块的)进度条.复选框.缩放按钮以及切换按钮等等. 在UI ...

  3. 第三部分:Android 应用程序接口指南---第二节:UI---第四章 Action Bar

    第4章 Action Bar Action Bar是一个能用于确定应用程序和用户的位置,并提供给用户操作和导航模式的窗口功能.如果需要显著地展示当前用户的操作或导航,应该使用Action Bar,因为 ...

  4. 第三部分:Android 应用程序接口指南---第二节:UI---第五章 设置(Settings)

    第5章 设置(Settings) 应用程序通常包括允许用户修改应用程序的特性和行为的设置功能.例如,一些应用程序允许用户指定通知是否启用或指定多久使用云同步数据.如果你想要为你的应用程序提供设置,你应 ...

  5. 第三部分:Android 应用程序接口指南---第二节:UI---第六章 对话框

    第6章 对话框 一个对话框是一个小窗口,提示用户做出决定或输入额外的信息,一个对话框不填充屏幕并且通常用于在程序运行时中断,然后弹出通知提示用户,从而直接影响到正在运行的程序.图6-1就是对话框的外观 ...

  6. 第三部分:Android 应用程序接口指南---第二节:UI---第八章 Toast通知

    第8章 Toast通知 Toast通知是在窗口前面弹出的信息.它只占有信息所需要的空间量,并且用户当前的activity仍然是可见的.可互动的.这种通知自动地淡入和淡出,它不接受交互事件.他相当于一种 ...

  7. 第三部分:Android 应用程序接口指南---第二节:UI---第九章 搜索

    第9章 搜索 在android平台上搜索是一个核心的用户功能.无论内容位于设备或网络上,用户应该能够搜索任何对它们可用的数据.为了创建一个一致的用户搜索体验,Android平台提供了一个搜索框架帮助你 ...

  8. 第三部分:Android 应用程序接口指南---第二节:UI---第十一章 样式和主题

    第11章 样式和主题 style是用于指定View或window的外观和格式的一系列属性的集合.style可以指定高(height).填补(padding).字体颜色.字体大小.背景颜色等等属性.st ...

  9. 第三部分:Android 应用程序接口指南---第二节:UI---第三章 菜单

    第3章 菜单 在许多不同类型的应用中,菜单通常是一种用户界面组件.为了提供给用户提供熟悉且一致的体验,你需要使用菜单API来展示用户动作和你Activity中的其他选项. 从安卓3.0系统(API l ...

随机推荐

  1. 013 JstlView

    一:InternalResourceViewResolver 1.InternalResourceViewResolver JSP是常见的视图技术,可以使用InternalResourceViewRe ...

  2. 091实战 Nginx配置(日志服务器中关于日志的产生)

    一:概括 1.需要配置的概括 定义日志格式 日志的分割字段:^A 日志格式:IP地址^A服务器时间^A请求参数 配置location,记录请求日志到本地磁盘 将数据按照给定的日志格式存储到本地磁盘 二 ...

  3. DP-hdu1176

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1176 这道题与动态规划中的数塔问题十分类似,因此如果对于数塔问题还不太明白的,可以先参考一下博客: 数 ...

  4. Ubuntu18.04更换国内源

    Ubuntu18.04更换国内源 Ubuntu本身的源使用的是国内的源,下载速度比较慢,不像CentOS一样yum安装的时候对镜像站点进项选择, 所以选择了更换成国内的源. 以下内容整合自网络 备份/ ...

  5. HTML的lang属性的作用

    今天翻了一下<css权威指南>选择器章节,看到伪类选择器,也叫语言选择器:lang(language),顾名思义它会根据html设置的语言应用对应样式,如: *:lang(en){ col ...

  6. ApplicationListener<ContextRefreshedEvent>接口,Spring启动后获取所有拥有特定注解的Bean

    最近项目中遇到一个业务场景,就是在Spring容器启动后获取所有的Bean中实现了一个特定接口的对象,第一个想到的是ApplicationContextAware,在setApplicationCon ...

  7. 4826: [Hnoi2017]影魔

    4826: [Hnoi2017]影魔 https://lydsy.com/JudgeOnline/problem.php?id=4826 分析: 莫队+单调栈+st表. 考虑如何O(1)加入一个点,删 ...

  8. Python中的正则表达式探秘1

    正则表达式中的特殊字符: $ 匹配输入字符串的结尾位置.如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n' 或 '\r'.要匹配 $ 字符本身,请使用 \$. ( ) ...

  9. CSDN博客文章的备份及导出电子书CHM

    需要用到的工具集合下载:http://download.csdn.net/source/2881423 在CSDN.百度等写博客文章的应该很多,很多时候担心服务器有一天突然挂了,或者担心自己的号被封了 ...

  10. 网站SSL证书在线检测

    网站SSL证书在线检测 http://web.chacuo.net/netsslcheck OpenSSL命令行工具的证书操作 http://blog.csdn.net/a351945755/arti ...