Notification(通知)是Android系统中比较有特色的一个功能,当某个应用程序希望向用户发出一些提示信息,而该应用程序又不在前台运行时,就可以借助通知来实现。

发出一条通知后,手机最上方的状态栏中会显示一个通知的图标,下拉状态栏后可以看到通知的详细内容。

Notification基本用法

要使用Notification,需要将其创建,创建Notification的步骤如下:

  1. 获取NotificationManager来对通知进行管理,调用Context的getSystemService() 方法获取到,getSystemService() 方法接收一个字符串参数用于确定获取系统的哪个服务,获取Notification服务则传入NOTIFICATION_SERVICE
    NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
  2. 使用一个Builder构造器来创建Notification对象,由于Android系统的每一个版本都会对通知这部分功能进行或多或少的修改,与通知相关的API有很大的不稳定性,所以使用Android扩展库的API来构建Notification对象(support库或是androidx库,在项目中二者不能同时存在)
    Android扩展库提供了一个NotificationCompat类,使用这个类的构造器来创建Notification 对象,就可以保证程序在所有Android系统版本上都能正常工作了
    Notification notification = new NotificationCompat.Builder(context).build();
  3. 在调用build()之前可以连缀任意多的设置方法来创建一个丰富的Notification对象
    Notification notification = new NotificationCompat.Builder(this)
         .setContentTitle("This is content title")
         .setContentText("This is content text")
         .setWhen(System.currentTimeMillis())
         .setSmallIcon(R.drawable.resizeapis)
         .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.resizeapi))
         .setContentIntent(pi)
         .setAutoCancel(true)
         .build();
    常用的方法如下:
    • setContentTitle() :指定通知的标题内容,下拉系统状态栏可以看到这部分内容
    • setContentText() :指定通知的正文内容,下拉系统状态栏可以看到这部分内容
    • setWhen() :指定通知被创建的时间,以毫秒为单位,当下拉系统状态栏时,这里指定的时间会显示在相应的通知上
    • setSmallIcon() :设置通知的小图标,注意只能使用纯alpha图层的图片进行设置,小图标会显示在系统状态栏上
    • setLargeIcon() :设置通知的大图标,当下拉系统状态栏时,可以看到设置的大图标
  4. 调用NotificationManager的notify() 方法让通知显示出来
    manager.notify(1, notification);
    public void notify(int id, Notification notification);
    • int id:与通知一一对应,必须是唯一值
    • Notification notification:自定义构建的Notification对象

应用程序的通知是可以点击并执行相应的动作,要实现通知的点击效果,还需要借助PendingIntent

PendingIntent和Intent有些类似,不同的是,Intent更加倾向于去立即执行某个动作,而PendingIntent更加倾向于在某个合适的时机去执行某个动作。可以把PendingIntent简单地理解为延迟执行的Intent
PendingIntent提供了几个静态方法用于获取PendingIntent的实例,可以根据需求来选择是使用getActivity() 方法、getBroadcast() 方法,还是getService() 方法

public static PendingIntent getActivity(Context context, int requestCode, Intent intent, @Flags int flags);
public static PendingIntent getBroadcast(Context context, int requestCode, Intent intent, @Flags int flags);
public static PendingIntent getService(Context context, int requestCode, Intent intent, @Flags int flags);

这三个方法所接收的参数都是相同的:

  • Context context:context对象,一般传入当前Activity
  • int requestCode:返回码,一般用不到,传入0
  • Intent intent:自定义构建的Intent对象
  • int flags:确定PendingIntent的行为,有FLAG_ONE_SHOT 、FLAG_NO_CREATE 、FLAG_CANCEL_CURRENT 和FLAG_UPDATE_CURRENT 这4种值可选

在NotificationCompat.Builder这个构造器后再连缀一个setContentIntent() 方法,将构建的PendingIntent对象作为参数传入

Intent intent = new Intent(this, NotificatoinActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(this)
        .setContentTitle("This is content title")
        .setContentText("This is content text")
        .setWhen(System.currentTimeMillis())
        .setSmallIcon(R.drawable.resizeapis)
        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.resizeapi))
        .setContentIntent(pi)
        .setAutoCancel(true)
        .build();
manager.notify(1, notification);

一般通知点击之后就会消失,需要在代码中对该通知进行取消。
有两种方法:

  • 在NotificationCompat.Builder 中再连缀一个setAutoCancel() 方法
    Notification notification = new NotificationCompat.Builder(this)
          ...
          .setAutoCancel(true)
          .build();
  • 显式地调用NotificationManager的cancel() 方法将它取消
    NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    //创建通知的时候给每条通知指定的id作为参数传入
    manager.cancel(1);

Android 8.0系统的Notification

在Android 8.0及以上的系统,Notification使用有些不同

    NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.notification_icon)
            .setContentTitle(textTitle)
            .setContentText(textContent)
            .setPriority(NotificationCompat.PRIORITY_DEFAULT);

NotificationCompat.Builder构造函数要求传入提供渠道 ID。这是兼容 Android 8.0(API 级别 26)及更高版本所必需的,但会被较旧版本忽略。

要能够在 Android 8.0 及更高版本上提供通知,首先必须向 createNotificationChannel() 传递 NotificationChannel 的实例,以便在系统中注册应用的通知渠道,这样才能在Android 8.0以上系统显示通知

    private void createNotificationChannel() {
        // Android 8.0及以上系统创建NotificationChannel
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = getString(R.string.channel_name);
            String description = getString(R.string.channel_description);
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
            channel.setDescription(description);
            // 向系统注册通道;在此之后不能更改重要性或其他通知行为
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }

必须先创建通知渠道,然后才能在 Android 8.0 及更高版本上发布任何通知,因此应在应用启动时立即执行这段代码
NotificationChannel常用属性如下:

// 配置通知渠道的属性
notificationChannel .setDescription("渠道的描述");
// 设置通知出现时的闪灯(如果 android 设备支持的话)
notificationChannel .enableLights(true);
notificationChannel .setLightColor(Color.RED);
// 设置通知出现时的震动(如果 android 设备支持的话)
notificationChannel .enableVibration(true);
notificationChannel .setVibrationPattern(new long[]{1000, 2000, 1000,3000});
//如上设置使手机:静止1秒,震动2秒,静止1秒,震动3秒

Notification其他操作

NotificationCompat.Builder中提供了非常丰富的API来创建更加多样的通知效果

  • setSound():在通知发出的时候播放一段音频,接收一个Uri 参数,所以在指定音频文件的时候还需要先获取到音频文件对应的URI
    Notification notification = new NotificationCompat.Builder(this)
          ...
          .setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg")))
          .build();
  • setVibrate():在通知到来的时候让手机进行振动,传入一个长整型的数组,用于设置手机静止和振动的时长,以毫秒为单位。下标为0的值表示手机静止的时长,下标为1的值表示手机振动的时长,下标为2的值又表示手机静止的时长
    Notification notification = new NotificationCompat.Builder(this)
          ...
          .setVibrate(new long[] {0, 1000, 1000, 1000 })
          .build();
    控制手机振动还需要声明权限
    <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.notificationtest"
      android:versionCode="1"
      android:versionName="1.0" >
      ...
      <uses-permission android:name="android.permission.VIBRATE" />
      ...
    </manifest>
  • setLights():在通知到来时控制手机LED灯的显示(支持LED的手机)
    Notification notification = new NotificationCompat.Builder(this)
      ...
      .setLights(Color.GREEN, 1000, 1000)
      .build();
    public Builder setLights(@ColorInt int argb, int onMs, int offMs);
    • int argb:指定LED灯的颜色
    • int onMs:指定LED灯亮起的时长,以毫秒为单位
    • int offMs:指定LED灯暗去的时长,以毫秒为单位
  • setDefaults():设置默认通知行为
    Notification notification = new NotificationCompat.Builder(this)
          ...
          .setDefaults(NotificationCompat.DEFAULT_ALL)
          .build();
  • setStyle():构建出富文本的通知内容,在通知中不光可以有文字和图标,还可以包含更多的东西
    public Builder setStyle(Style style);
    • Style style:NotificationCompat.Style参数,这个参数就是用来构建具体的富文本信息的
    • NotificationCompat提供了丰富的Style参数,利用这些来构建程序
  • setPriority():设置这条通知的重要程度,一共有5个常量值可选:
    • PRIORITY_DEFAULT:表示默认的重要程度;
    • PRIORITY_MIN:表示最低的重要程度,系统可能只会在特定的场景才显示这条通知;
    • PRIORITY_LOW:表示较低的重要程度,系统可能会将这类通知缩小,或改变其显示的顺序,将其排在更重要的通知之后;
    • PRIORITY_HIGH:表示较高的重要程度,系统可能会将这类通知放大,或改变其显示的顺序,将其排在比较靠前的位置;
    • PRIORITY_MAX:表示最高的重要程度,这类通知消息必须要让用户立刻看到,甚至需要用户做出响应操作