Android通知Notification详解

    • Notification的使用大体步骤
    • Notification简介
    • PendingIntent简介
    • 使用RemoteViews自定义Notification
    • 更新与移除通知
    • 设定提示响应
    • 附录

Notification的使用大体步骤:

1、 获取状态通知栏管理
2、 实例化通知栏构造器
3、 设置NotificationCompat.Builder
4、 设置PendingIntent
5、 显示

因为Android的快速发展,而Android的版本也快速的升级导致了一些兼容性的问题。对于Notification而言,Android3.0是一个分水岭,在其之前构建Notification推荐使用NotificationCompate.Builder,是一个Android向下版本的兼容包,而在Android3.0之后,一般推荐使用Notification.Builder构建。本博客主要介绍的是Android4.x的开发,所以在这里使用Notification.Builder进行讲解演示。

虽然通知中提供了各种属性的设置,但是一个通知对象,有几个属性是必须要设置的,其他的属性均是可选的,必须设置的属性如下:
1)、小图标,使用setSamllIcon()方法设置。
2)、标题,使用setContentTitle()方法设置。
3)、文本内容,使用setContentText()方法设置。

Notification简介

Notification有两种视觉风格,一种是标准视图(Normal View)、一种是大视图(Big view)。标准视图在Android中各版本是通用的,但是对于大视图而言,仅支持Android4.1+的版本。
Notification.flags属性参数:(是否可以设置多个):
从官方文档了解到,一个标准视图显示的大小保持在64dp高。如下图所示:
Android通知Notification详解_第1张图片
1、 通知标题
2、 大图标
3、 通知内容
4、 通知消息
5、 小图标
6、 通知时间,一般为系统时间,也可以使用setWhen()设置。

而对于大视图(Big View)而言,它的细节区域只能显示256dp高度的内容,并且只对Android4.1+之后的设备才支持,它比标准视图不一样的地方,均需要使用setStyle()方法设定,它大致的效果如下:
Android通知Notification详解_第2张图片
Android为我们提供了三个实现类,用于显示不同的场景。分别是:
Notification.BigPictureStyle, 在细节部分显示一个256dp高度的位图。
Notification.BigTextStyle,在细节部分显示一个大的文本块。
Notification.InboxStyle,在细节部分显示一段行文本

Notification.FLAG_SHOW_LIGHTS //三色灯提醒,在使用三色灯提醒时候必须加该标志符
Notification.FLAG_ONGOING_EVENT //发起正在运行事件(活动中)
Notification.FLAG_INSISTENT //让声音、振动无限循环,直到用户响应 (取消或者打开)
Notification.FLAG_ONLY_ALERT_ONCE //发起Notification后,铃声和震动均只执行一次
Notification.FLAG_AUTO_CANCEL //用户单击通知后自动消失
Notification.FLAG_NO_CLEAR //只有全部清除时,Notification才会清除 ,不清楚该通知(QQ的通知无法清除,就是用的这个。还有百度通知栏里面的搜索框也是这个)。
使用方法:在设置完属性后,设置
Notification notification = builder.build();
notification.flags = Notification.FLAG_ONLY_ALERT_ONCE;

PendingIntent简介

对于一个通知而言,它显示的消息是有限的,一般仅用于提示一些概要信息。但是一般简短的消息,并不能表达需要告诉用户的全部内容,所以需要绑定一个意图,当用户点击通知的时候,调用一个意图展示出一个Activity用来显示详细的内容。而Notification中,并不使用常规的Intent去传递一个意图,而是使用PendingIntent。
先来说说Intent和PendingIntent的区别,PendingIntent可以看做是对Intent的包装,通过名称可以看出PendingIntent用于处理即将发生的意图,而Intent用来用来处理马上发生的意图。而对于通知来说,它是一系统级的全局通知,并不确定这个意图被执行的时间。当在应用外部执行PendingIntent时,因为它保存了触发应用的Context,使得外部应用可以如在当前应用中一样,执行PendingIntent里的Intent,就算执行的时候响应通知的应用已经被销毁了,也可以通过存在PendingIntent里的Context照常执行它,并且还可以处理Intent说带来的额外信息。
PendingInteng.getBroadcast(contex, requestCode, intent, flags)
PendingInteng.getService(contex, requestCode, intent, flags)
PendingInteng.getActivity(contex, requestCode, intent, flags)
PendingInteng.getActivities(contex, requestCode, intent, flags)
其中flags属性参数:
FLAG_ONE_SHOT 表示返回的PendingIntent仅能执行一次,执行完后自动消失
FLAG_NO_CREATE 表示如果描述的PendingIntent不存在,并不创建相应的PendingIntent,而是返回NULL
FLAG_CANCEL_CURRENT 表示相应的PendingIntent已经存在,则取消前者,然后创建新的PendingIntent
FLAG_UPDATE_CURRENT 表示更新的PendingIntent,如果构建的PendingIntent已经存在,则替换它,常用。

使用RemoteViews自定义Notification

需要使用RemoteViews.RemoteViews描述了一个视图层次的结构,可以显示在另一个进程。RemoteViews提供了多个构造函数,一般使用RemoteViews(String packageName,int layoutId)。第一个参数为包的名称,第二个为layout资源的Id。当获取到RemoteViews对象之后,可以使用它的一系列setXxx()方法通过控件的Id设置控件的属性。最后使用NotificationCompat.Builder.setContent(RemoteViews)方法设置它到一个Notification中。
remoteViews.setOnClickPendingIntent(viewId, pendingIntent);可以进入不同的Activity。如:
remoteViews.setOnClickPendingIntent(R.id.titleTV, PendingIntent.getActivity(context, 0,
new Intent(context, ScrollingActivity.class), PendingIntent.FLAG_UPDATE_CURRENT));

更新与移除通知

在使用NotificationManager.notify()发送通知的时候,需要传递一个标识符,用于唯一标识这个通知。对于有些场景,并不是无限的添加新的通知,有时候需要更新原有通知的信息,这个时候可以重写构建Notification,而使用与之前通知相同标识符来发送通知,这个时候旧的通知就被被新的通知所取代,起到更新通知的效果。
对于一个通知,当展示在状态栏之后,但是使用过后,如何取消呢?Android为我们提供两种方式移除通知,一种是Notification自己维护,使用setAutoCancel()方法设置是否维护,传递一个boolean类型的数据。另外一种方式使用NotificationManager通知管理器对象来维护,它通过notify()发送通知的时候,指定的通知标识Id来操作通知,可以使用cancel(int)来移除一个指定的通知,也可以使用cancelAll()移除所有的通知。
使用NotificationManager移除指定通知示例:

NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancel(0);

设定提示响应

对于有些通知,需要调用一些设备的资源,使用户能更快的发现有新通知,一般可设定的响应有:铃声、闪光灯、震动。对于这三个属性,NotificationCompat.Builder提供了三个方法设定:
setSound(Uri sound):设定一个铃声,用于在通知的时候响应。传递一个Uri的参数,格式为“file:///mnt/sdcard/Xxx.mp3”。
setLights(int argb, int onMs, int offMs):设定前置LED灯的闪烁速率,持续毫秒数,停顿毫秒数。
setVibrate(long[] pattern):设定震动的模式,以一个long数组保存毫秒级间隔的震动。
大多数时候,我们并不需要设定一个特定的响应效果,只需要遵照用户设备上系统通知的效果即可,那么可以使用setDefaults(int)方法设定默认响应参数,在Notification中,对它的参数使用常量定义了,我们只需使用即可:
DEFAULT_ALL:铃声、闪光、震动均系统默认。
DEFAULT_SOUND:系统默认铃声。
DEFAULT_VIBRATE:系统默认震动。
DEFAULT_LIGHTS:系统默认闪光。
设置震动,需要权限:android.permission.VIBRATE
设置闪光灯,需要权限:android.permission.FLASHLIGHT

附录

下面是我封装的一个通知工具类:

package com.test.testandroid;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.widget.RemoteViews;

/** * Created by Administrator on 2016-6-19. * notification builder android */
public class NotificationUtil {
    private Context context;
    private NotificationManager notificationManager;
    public NotificationUtil(Context context) {
        this.context = context;
        notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    }

    /** * 普通的Notification */
    public void postNotification() {
        Notification.Builder builder = new Notification.Builder(context);
        Intent intent = new Intent(context, MainActivity.class);  //需要跳转指定的页面
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentIntent(pendingIntent);
        builder.setSmallIcon(R.mipmap.ic_launcher);// 设置图标
        builder.setContentTitle("标题");// 设置通知的标题
        builder.setContentText("内容");// 设置通知的内容
        builder.setWhen(System.currentTimeMillis());// 设置通知来到的时间
        builder.setAutoCancel(true); //自己维护通知的消失
        builder.setTicker("new message");// 第一次提示消失的时候显示在通知栏上的
        builder.setOngoing(true);
        builder.setNumber(20);

        Notification notification = builder.build();
        notification.flags = Notification.FLAG_NO_CLEAR;  //只有全部清除时,Notification才会清除
        notificationManager.notify(0,notification);
    }

    /** * 使用下载的Notification,在4.0以后才能使用<p></p> * Notification.Builder类中提供一个setProgress(int max,int progress,boolean indeterminate)方法用于设置进度条, * max用于设定进度的最大数,progress用于设定当前的进度,indeterminate用于设定是否是一个确定进度的进度条。 * 通过indeterminate的设置,可以实现两种不同样式的进度条,一种是有进度刻度的(true),一种是循环流动的(false)。 */
    public void postDownloadNotification() {
        final Notification.Builder builder = new Notification.Builder(context);
        builder.setSmallIcon(R.mipmap.ic_launcher)
                .setTicker("showProgressBar").setContentInfo("contentInfo")
                .setOngoing(true).setContentTitle("ContentTitle")
                .setContentText("ContentText");
        // 模拟下载过程
        new Thread(new Runnable() {
            @Override
            public void run() {
                int progress ;
                for (progress = 0; progress < 100; progress += 5) {
                    // 将setProgress的第三个参数设为true即可显示为无明确进度的进度条样式
                    builder.setProgress(100, progress, false);
                    notificationManager.notify(0, builder.build());
                    try {
                        Thread.sleep(1 * 1000);
                    } catch (InterruptedException e) {
                        System.out.println("sleep failure");
                    }
                }
                builder.setContentTitle("Download complete")
                        .setProgress(0, 0, false).setOngoing(false);
                notificationManager.notify(0, builder.build());
            }
        }).start();
    }

    /** * 大视图通知在4.1以后才能使用,BigTextStyle<p></p> * ****************************************************<p></p> * Helper class for generating large-format notifications that include a lot of text. * * Here's how you'd set the <code>BigTextStyle</code> on a notification: * <pre class="prettyprint"> * Notification notif = new Notification.Builder(mContext) * .setContentTitle(&quot;New mail from &quot; + sender.toString()) * .setContentText(subject) * .setSmallIcon(R.drawable.new_mail) * .setLargeIcon(aBitmap) * .setStyle(new Notification.BigTextStyle() * .bigText(aVeryLongString)) * .build(); * </pre> * * @see Notification#bigContentView */
    public void postBigTextNotification() {
        Notification.BigTextStyle textStyle = new Notification.BigTextStyle();
        textStyle.setBigContentTitle("大标题")
                // 标题
                .setSummaryText("SummaryText")
                .bigText("Helper class for generating large-format notifications" +
                        " that include a lot of text; !!!!!!!!!!!" +
                        "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
        Notification.Builder builder2 = new Notification.Builder(
                context);
        builder2.setSmallIcon(R.mipmap.ic_launcher);// 小图标
        // 大图标
        builder2.setLargeIcon(BitmapFactory.decodeResource(
                context.getResources(), R.mipmap.ic_launcher));  //R.mipmap.close
        builder2.setTicker("showBigView_Text")
                .setContentInfo("contentInfo");
        builder2.setStyle(textStyle);
        builder2.setAutoCancel(true);

        notificationManager.notify(0, builder2.build());
    }

    /** * 大布局通知在4.1以后才能使用,大布局图片 */
    public void postBigPictureNotification() {
        Notification.BigPictureStyle bigPictureStyle = new Notification.BigPictureStyle();
        bigPictureStyle.bigPicture(BitmapFactory.decodeResource(context.getResources(),
                R.mipmap.ic_launcher));  //R.drawable.back

        Notification.Builder builder = new Notification.Builder(
                context);
        builder.setSmallIcon(R.mipmap.ic_launcher);// 小图标
        // 大图标
        builder.setLargeIcon(BitmapFactory.decodeResource(
                context.getResources(), R.drawable.ic_stop));
        builder.setTicker("showBigView_Picture")
                .setContentInfo("contentInfo");
        builder.setStyle(bigPictureStyle);
        builder.setAutoCancel(true);

        notificationManager.notify(0, builder.build());
    }

    /** * 大布局通知在4.1以后才能使用,InboxStyle */
    public void postInboxNotification() {
        Notification.InboxStyle inboxStyle = new Notification.InboxStyle();
        inboxStyle.setBigContentTitle("InboxStyle");
        inboxStyle.setSummaryText("Test");
        for(int i = 0 ; i < 10; i++){
            inboxStyle.addLine("new:" + i);
        }

        Notification.Builder builder5 = new Notification.Builder(
                context);
        builder5.setSmallIcon(R.mipmap.ic_launcher);// 小图标
        // 大图标
        builder5.setLargeIcon(BitmapFactory.decodeResource(
                context.getResources(), R.drawable.ic_stop));
        builder5.setTicker("showBigView_InboxStyle")
                .setContentInfo("contentInfo");
        builder5.setStyle(inboxStyle);
        builder5.setAutoCancel(true);

        notificationManager.notify(0, builder5.build());
    }

    /** * 自定义通知<p></p> * * 不设置notification.contentIntent = pendingIntent;则报如下异常: * android.app.RemoteServiceException: * Bad notification posted from package com.test.testandroid: Couldn't expand RemoteViews for: StatusBarNotification( * pkg=com.test.testandroid user=UserHandle{0} id=0 tag=null score=0 key=0|com.test.testandroid|0|null|10168|0: Notification * (pri=0 contentView=com.test.testandroid/0x7f040038 vibrate=null sound=null defaults=0x0 flags=0x10 color=0xff00aeff vis=PRIVATE)) */
    public void postCustomNotification() {
        RemoteViews contentViews = new RemoteViews(context.getPackageName(),
                R.layout.mynotification);
        contentViews.setImageViewResource(R.id.imageNotifi,R.mipmap.ic_launcher);
        contentViews.setTextViewText(R.id.titleTV,"自定义通知标题");
        contentViews.setTextViewText(R.id.textTV,"自定义通知内容");

        Intent intent = new Intent(context, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        contentViews.setOnClickPendingIntent(R.id.titleTV, pendingIntent);
        contentViews.setOnClickPendingIntent(R.id.textTV, PendingIntent.getActivity(context, 0,
                new Intent(context, ScrollingActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);

        Notification.Builder builder = new Notification.Builder(context);
        builder.setSmallIcon(R.mipmap.ic_launcher);
        builder.setContentTitle("custom notification");
        builder.setContentText("custom test");
        builder.setTicker("custom ticker");
        builder.setAutoCancel(true);
        builder.setContent(contentViews);

        notificationManager.notify(0,builder.build());
    }

    public void cancelById() {
        notificationManager.cancel(0);  //对应NotificationManager.notify(id,notification);第一个参数
    }

    public void cancelAllNotification() {
        notificationManager.cancelAll();
    }
}

使用方法:

NotificationUtil notiUtil = new NotificationUtil(this);
// notiUtil .postNotification();
// notiUtil .postDownloadNotification();
// notiUtil .postBigTextNotification();
// notiUtil .postBigPictureNotification();
// notiUtil .postCustomNotification();
        notiUtil .postInboxNotification();

其中自定义的postCustomNotification()运行结果如下图:
Android通知Notification详解_第3张图片
布局怎么都不能居中,后来使用了如下的方法:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="center" android:gravity="center_vertical">

    <RelativeLayout  android:layout_width="wrap_content" android:layout_height="36dp" android:gravity="center" android:layout_gravity="center" android:background="@drawable/bg">

        <ImageView  android:id="@+id/imageNotifi" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:gravity="center_vertical" />
            。。。。。

不知是否还有更好的办法。

参考:
(1)Android-通知之Notification;
(2)Android通知栏Notification整合;

你可能感兴趣的:(android,RemoteView,Notificati,PendingInt)