您的位置:首页 > 产品设计 > UI/UE

安卓通知与NotificationCompat.Builder

2017-09-29 15:01 459 查看
安卓更新挺快,以至于之前学的关于通知的使用方法都过时了

现在重新再写个文章记录一下

创建通知

Android 3.0 (API level 11)之前,使用
new
Notification()
方式创建通知:

NotificationManager mNotifyMgr =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(
this, 0, new Intent(this, ResultActivity.class), 0);

Notification notification = new Notification(icon, tickerText, when);
notification.setLatestEventInfo(this, title, content, contentIntent);

mNotifyMgr.notify(NOTIFICATIONS_ID, notification);


Android 3.0 (API level 11)及更高版本,改用
Notification.Builder()
来创建通知:

NotificationManager mNotifyMgr =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(
this, 0, new Intent(this, ResultActivity.class), 0);

Notification notification = new Notification.Builder(this)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Hello World!")
.setContentIntent(contentIntent)
.build();// getNotification()

mNotifyMgr.notify(NOTIFICATIONS_ID, notification);

这里需要注意: "build()" 是Androdi 4.1(API level 16)加入的,用以替代
"getNotification()"。API level 16开始弃用"getNotification()"


通知基本用法

一个通知必须包含以下三项属性:

小图标,对应 setSmallIcon()
通知标题,对应 setContentTitle()
详细信息,对应 setContentText()
其他属性均为可选项,更多属性方法请参考NotificationCompat.Builder

尽管其他都是可选的,但一般都会为通知添加至少一个动作(Action),这个动作可以是跳转到Activity、启动一个Service或发送一个Broadcas等。 通过以下方式为通知添加动作:

使用PendingIntent
通过大视图通知的 Action Button //仅支持Android 4.1 (API level 16)及更高版本,稍后会介绍


创建通知

1、实例化一个NotificationCompat.Builder对象
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("我是头部")
.setContentText("内容内容内容内容内容内容内容内容");


NotificationCompat.Builder会自动设置默认值:
priority: PRIORITY_DEFAULT           --------优先级,有五个优先级别,范围从 
PRIORITY_MIN
 (-2)
到 
PRIORITY_MAX
 (2);默认为 
PRIORITY_DEFAULT
 (0)。
when: System.currentTimeMillis()--------通知创建的时间,有的手机会显示,有的不会
audio stream: STREAM_DEFAULT--------当声音响起时,所用的音频流的类型
2、定义并设置一个通知动作(Action)

PendingIntent类封装了一个Intent和一个动作,当调用该类的send方法的时候,将会执行该动作。由于PendingIntent类是一个待处理的意图,这个动作通常是在将来的某个时刻要调用的一个操作,很可能是系统要调用的。

PendingIntent类中的动作是Context类中的几个方法之一,例如startActivity,startService,sendBroadcast

使用PendingIntent来启动一个Activity

Intent resultIntent = new Intent(this, ResultActivity.class);
PendingIntent resultPendingIntent = PendingIntent.getActivity(
this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);

PendingIntent pi = PendingIntent.getActivity(Context context, int requestCode,Intent intent, int flags);


静态方法getActivity是返回PendingIntent类的一个实例的几个方法之一,其他的方法还有getActivities、getService和getBroadcast

这些方法决定了最终PendingIntent所能执行的动作,可以用来启动Activity,启动Service,发送广播等

3、NotificationManager

要发布一个通知,可以使用NotificationManager,这是Android系统中的内建服务之一,是一个已有的系统服务,可以通过如下代码来获取它
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);


然后,在该NotificationManager上调用notify方法来发布一个通知,需要传入唯一的ID和Notification对象
mNotificationManager.notify(int id, notification);


注意这里要求传入的是notification,但是我们创建的是NotificationCompat.Builder,这时候你需要生成
Notification
对象

Notificatioin notification = Builder.build();

通知ID用于标识该通知,在想要取消特定Notification的时候,就需要使用到它

mNotificationManager.cancel(int id);


此外,除非发生以下情况之一,否则通知会一直可见:

用户单独或通过使用“全部清除”清除了该通知(如果通知可以清除)
用户点击通知,且在创建通知时调用了 setAutoCancel(true)
针对特定的通知 ID 调用了 cancel(int id)
调用了 cancelAll() 方法,该方法将删除之前发出的所有通知


更新通知

更新通知很简单,只需再次发送相同ID的通知即可,如果之前的通知依然存在则会更新通知属性,如果之前通知不存在则重新创建。

取消通知

取消通知有如下4种方式:

点击通知栏的清除按钮,会清除所有可清除的通知
设置了 setAutoCancel() 或 FLAG_AUTO_CANCEL的通知,点击该通知时会清除它
通过 NotificationManager 调用 cancel() 方法清除指定ID的通知
通过 NotificationManager 调用 cancelAll() 方法清除所有该应用之前发送的通知


创建简单通知

private int id = 1;

public void notification(View view) {
Drawable drawable = ContextCompat.getDrawable(this, R.drawable.ic_submit);
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
//设置小图标
mBuilder.setSmallIcon(R.mipmap.ic_launcher);
//设置大图标
mBuilder.setLargeIcon(bitmap);
//设置标题
mBuilder.setContentTitle("这是标题");
//设置通知正文
mBuilder.setContentText("这是正文,当前ID是:" + id);
//设置摘要
mBuilder.setSubText("这是摘要");
//设置是否点击消息后自动clean
mBuilder.setAutoCancel(true);
//在通知的右边设置大的文本。
mBuilder.setContentInfo("右侧文本");
//与setContentInfo类似,但如果设置了setContentInfo则无效果
//用于当显示了多个相同ID的Notification时,显示消息总数
mBuilder.setNumber(2);
//通知在状态栏显示时的文本
mBuilder.setTicker("在状态栏上显示的文本");
//设置优先级
mBuilder.setPriority(NotificationCompat.PRIORITY_MAX);
//自定义消息时间,以毫秒为单位,当前设置为比系统时间少一小时
mBuilder.setWhen(System.currentTimeMillis() - 3600000);
//设置为一个正在进行的通知,此时用户无法清除通知
mBuilder.setOngoing(true);
//设置消息的提醒方式,震动提醒:DEFAULT_VIBRATE     声音提醒:NotificationCompat.DEFAULT_SOUND
//三色灯提醒NotificationCompat.DEFAULT_LIGHTS     以上三种方式一起:DEFAULT_ALL
mBuilder.setDefaults(NotificationCompat.DEFAULT_SOUND);
//设置震动方式,延迟零秒,震动一秒,延迟一秒、震动一秒
mBuilder.setVibrate(new long[]{0, 1000, 1000, 1000});

Intent intent = new Intent(this, ShadowTextViewActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);
mBuilder.setContentIntent(pIntent);

NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(id++, mBuilder.build());
}

public void cleanNotification(View view) {
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancelAll();
mNotificationManager.cancel(1);
}


效果如下



通知类型

大视图通知

通知有两种视图:普通视图和大视图。
普通视图:



大视图:



默认情况下为普通视图,可通过
NotificationCompat.Builder.setStyle()
设置大视图。

注: 大视图(Big Views)由Android 4.1(API level 16)开始引入,且仅支持Android 4.1及更高版本。


构建大视图通知

Drawable drawable = ContextCompat.getDrawable(this, R.drawable.ic_submit);
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
//设置小图标
mBuilder.setSmallIcon(R.mipmap.ic_launcher);
//设置大图标
mBuilder.setLargeIcon(bitmap);
//设置标题
mBuilder.setContentTitle("这是标题");
//设置通知正文
mBuilder.setContentText("这是正文,当前ID是:" + id);
//设置优先级
mBuilder.setPriority(NotificationCompat.PRIORITY_MAX);
//设置为一个正在进行的通知,此时用户无法清除通知
mBuilder.setOngoing(true);
mBuilder.setDefaults(NotificationCompat.DEFAULT_SOUND);

Intent intent = new Intent(this, ShadowTextViewActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);
mBuilder.setContentIntent(pIntent);

// 该方法在Android 4.1之前会被忽略
mBuilder.setStyle(new NotificationCompat.BigTextStyle()
.bigText("这里可以显示一大串文字,你可以试试\n这里可以显示一大串文字,你可以试试\n这里可以显示一大串文字,你可以试试\n这里可以显示一大串文字,你可以试试"))
//添加Action Button
.addAction (R.mipmap.ic_launcher,
"取消", pIntent)
.addAction (R.mipmap.ic_launcher,
"确定", pIntent);

NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(id, mBuilder.build());


效果图如下



不仅可以放一大段文字,还能放一张大图哦!
Drawable drawable = ContextCompat.getDrawable(this, R.drawable.ic_loading_fail);
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();

NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentTitle("这是标题");
builder.setContentText("这是正文");
builder.setSmallIcon(R.drawable.ic_circulation);
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.ic_submit));
builder.setDefaults(NotificationCompat.DEFAULT_ALL);
builder.setAutoCancel(true);

NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle();
style.setBigContentTitle("展开后的标题");
style.setSummaryText("这是摘要");
style.bigPicture(bitmap);
builder.setStyle(style);

Intent intent = new Intent(this, ShadowTextViewActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);
builder.setContentIntent(pIntent);

NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(id, builder.build());

效果图如下






进度条通知

明确进度的进度条

使用
setProgress(max, progress, false)
来更新进度。

max: 最大进度值

progress: 当前进度

false: 是否是不明确的进度条

模拟下载过程,示例如下:

int id = 1;
...
mNotifyManager = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this);
mBuilder.setContentTitle("Picture Download")
.setContentText("Download in progress")
.setSmallIcon(R.drawable.ic_notification);

// Start a lengthy operation in a background thread
new Thread(
new Runnable() {
@Override
public void run() {
int incr;
for (incr = 0; incr <= 100; incr+=5) {
mBuilder.setProgress(100, incr, false);
mNotifyManager.notify(id, mBuilder.build());
try {
// Sleep for 5 seconds
Thread.sleep(5*1000);
} catch (InterruptedException e) {
Log.d(TAG, "sleep failure");
}
}
mBuilder.setContentText("Download complete")//下载完成
.setProgress(0,0,false);    //移除进度条
mNotifyManager.notify(id, mBuilder.build());
}
}
).start();




上图,分别为下载过程中进度条通知 和 下载完成移除进度条后的通知。

不确定进度的进度条

使用
setProgress(0, 0, true)
来表示进度不明确的进度条

mBuilder.setProgress(0, 0, true); mNotifyManager.notify(id, mBuilder.build());



启动 Activity 时保留导航

从通知中启动 
Activity
 时,您必须保留用户的预期导航体验。 点击“返回”应该使用户将应用的正常工作流回退到主屏幕,而点击“最新动态”则应将
Activity
 显示为单独的任务。
要保留导航体验,您应该在全新任务中启动 
Activity
。如何设置 
PendingIntent
 以获得全新任务取决于正在启动的
Activity
 的性质。一般有两种情况:

常规 Activity您要启动的 
Activity
 是应用的正常工作流的一部分。在这种情况下,请设置 
PendingIntent
 以启动全新任务并为 
PendingIntent
提供返回栈,这将重现应用的正常“返回”行为。
Gmail 应用中的通知演示了这一点。点击一封电子邮件消息的通知时,您将看到消息具体内容。 触摸返回将使您从 Gmail 回退到主屏幕,就好像您是从主屏幕(而不是通知)进入 Gmail 一样。
无论您触摸通知时处于哪个应用,都会发生这种情况。 例如,如果您在 Gmail 中撰写消息时点击了一封电子邮件的通知,则会立即转到该电子邮件。 触摸“返回”会依次转到收件箱和主屏幕,而不是转到您在撰写的邮件。
特殊 Activity仅当从通知中启动时,用户才会看到此 
Activity
。 从某种意义上说,
Activity
 是通过提供很难显示在通知本身中的信息来扩展通知。对于这种情况,请将 
PendingIntent
 设置为在全新任务中启动。但是,由于启动的 
Activity
 不是应用
Activity 流程的一部分,因此无需创建返回栈。点击“返回”仍会将用户带到主屏幕。

设置常规 Activity PendingIntent

要设置可启动直接进入 
Activity
 的 
PendingIntent
,请执行以下步骤:
在清单文件中定义应用的 
Activity
 层次结构。
添加对 Android 4.0.3 及更低版本的支持。为此,请通过添加 
<meta-data>
 元素作为 
<activity>
的子项来指定正在启动的 
Activity
 的父项。
对于此元素,请设置 
android:name="android.support.PARENT_ACTIVITY"

设置 
android:value="<parent_activity_name>"
,其中,
<parent_activity_name>
 是父 
<activity>
 元素的 
android:name
 值。请参阅下面的
XML 示例。

同样添加对 Android 4.1 及更高版本的支持。为此,请将 
android:parentActivityName
 属性添加到正在启动的 
Activity
 的 
<activity>
 元素中。
最终的 XML 应如下所示:
<activity
    android:name=".MainActivity"
    android:label="@string/app_name" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity
    android:name=".ResultActivity"
    android:parentActivityName=".MainActivity">
    <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value=".MainActivity"/>
</activity>


根据可启动 
Activity
 的 
Intent
 创建返回栈:
创建 
Intent
 以启动 
Activity

通过调用 
TaskStackBuilder.create()
 创建堆栈生成器。
通过调用 
addParentStack()
 将返回栈添加到堆栈生成器。
对于在清单文件中所定义层次结构内的每个 
Activity
,返回栈均包含可启动 
Activity
的 
Intent
 对象。此方法还会添加一些可在全新任务中启动堆栈的标志。

注:尽管 
addParentStack()
 的参数是对已启动 
Activity
 的引用,但是方法调用不会添加可启动 
Activity
 的 
Intent
,而是留待下一步进行处理。

通过调用 
addNextIntent()
,添加可从通知中启动 
Activity
 的 
Intent

将在第一步中创建的 
Intent
 作为 
addNextIntent()
 的参数传递。
如需,请通过调用 
TaskStackBuilder.editIntentAt()
 向堆栈中的 
Intent
 对象添加参数。有时,需要确保目标 
Activity
 在用户使用“返回”导航回它时会显示有意义的数据。
通过调用 
getPendingIntent()
 获得此返回栈的 
PendingIntent

然后,您可以使用此 
PendingIntent
 作为 
setContentIntent()
 的参数。

以下代码段演示了该流程:
...
Intent resultIntent = new Intent(this, ResultActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack
stackBuilder.addParentStack(ResultActivity.class);
// Adds the Intent to the top of the stack
stackBuilder.addNextIntent(resultIntent);
// Gets a PendingIntent containing the entire back stack
PendingIntent resultPendingIntent =
        stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
...
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(id, builder.build());

设置特殊 Activity PendingIntent

下文介绍如何设置特殊 Activity 
PendingIntent


特殊 
Activity
 无需返回栈,因此您不必在清单文件中定义其 
Activity
 层次结构,也不必调用 
addParentStack()
 来构建返回栈。取而代之的是,您可使用清单文件设置 
Activity
 任务选项,并通过调用 
getActivity()
 创建 
PendingIntent

在清单文件中,将以下属性添加到 
Activity
 的 
<activity>
 元素
android:name="activityclass"
Activity 的完全限定类名。
android:taskAffinity=""
与您在代码中设置的 
FLAG_ACTIVITY_NEW_TASK
 标志相结合,这可确保此 
Activity
 不会进入应用的默认任务。任何具有应用默认关联的现有任务均不受影响。
android:excludeFromRecents="true"
将新任务从“最新动态”中排除,这样用户就不会在无意中导航回它。以下代码段显示了该元素:
<activity
    android:name=".ResultActivity"
...
    android:launchMode="singleTask"
    android:taskAffinity=""
    android:excludeFromRecents="true">
</activity>
...


构建并发出通知:
创建可启动 
Activity
的 
Intent

通过使用 
FLAG_ACTIVITY_NEW_TASK
 和 
FLAG_ACTIVITY_CLEAR_TASK
 标志调用 
setFlags()
,将 
Activity
 设置为在新的空任务中启动。
为 
Intent
 设置所需的任何其他选项。
通过调用 
getActivity()
 从 
Intent
 中创建 
PendingIntent

然后,您可以使用此 
PendingIntent
 作为 
setContentIntent()
 的参数。
以下代码段演示了该流程:
// Instantiate a Builder object.
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
// Creates an Intent for the Activity
Intent notifyIntent =
        new Intent(this, ResultActivity.class);
// Sets the Activity to start in a new, empty task
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                        | Intent.FLAG_ACTIVITY_CLEAR_TASK);
// Creates the PendingIntent
PendingIntent notifyPendingIntent =
        PendingIntent.getActivity(
        this,
        0,
        notifyIntent,
        PendingIntent.FLAG_UPDATE_CURRENT
);

// Puts the PendingIntent into the notification builder
builder.setContentIntent(notifyPendingIntent);
// Notifications are issued by sending them to the
// NotificationManager system service.
NotificationManager mNotificationManager =
    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Builds an anonymous Notification object from the builder, and
// passes it to the NotificationManager
mNotificationManager.notify(id, builder.build());


自定义通知布局

您可以利用通知框架定义自定义通知布局,由该布局定义通知在 
RemoteViews
 对象中的外观。 自定义布局通知类似于常规通知,但是它们是基于 XML 布局文件中所定义的 
RemoteViews


自定义通知布局的可用高度取决于通知视图。普通视图布局限制为 64 dp,扩展视图布局限制为 256 dp。

要定义自定义通知布局,请首先实例化 
RemoteViews
 对象来扩充 XML 布局文件。然后,调用 
setContent()
,而不是调用 
setContentTitle()
 等方法。要在自定义通知中设置内容详细信息,请使用 
RemoteViews
 中的方法设置视图子项的值:
在单独的文件中为通知创建 XML 布局。您可以根据需要使用任何文件名,但必须使用扩展名 
.xml

在您的应用中,使用 
RemoteViews
 方法定义通知的图标和文本。通过调用 
setContent()
 将此 
RemoteViews
 对象放入 
NotificationCompat.Builder
中。避免在 
RemoteViews
 对象上设置背景 
Drawable
,因为文本颜色可能使文本变得难以阅读。

此外,
RemoteViews
 类中还有一些方法可供您轻松将 
Chronometer
 或 
ProgressBar
 添加到通知布局。如需了解有关为通知创建自定义布局的详细信息,请参阅 
RemoteViews
 参考文档。

注意:使用自定义通知布局时,要特别注意确保自定义布局适用于不同的设备方向和分辨率。 尽管这条建议适用于所有“视图”布局,但对通知尤为重要,因为抽屉式通知栏中的空间非常有限。 不要让自定义布局过于复杂,同时确保在各种配置中对其进行测试。

本文参考文章


全面了解Android Notification



Android Notification的使用

https://developer.android.com/guide/topics/ui/notifiers/notifications.html#Updating
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android notification