Android 基础:Notification

本文深入讲解Android中的通知机制,包括Notification的基本概念、属性设置、自定义布局、进度显示及锁屏显示等内容。同时介绍了如何设置震动、声音和呼吸灯等特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考:
Android基础入门教程——2.5.2 Notification(状态栏通知)详解
Android Notification 的声音和震动
google API guilde :https://developer.android.google.cn/guide/topics/ui/notifiers/notifications.html
demo:http://git.oschina.net/AndroidUI/CustomNotification01

Notification:就是服务器推送的消息,显示在手机最顶部的任务栏的消息。

有关的类和方法

类:

NotificationManager:通知管理器:可以发送和取消通知
Notification:通知对象,可以设置属性

方法:

常用方法

.setContentTitle("标题")
.setContentText("内容内容内容内容内容内容内容")
.setSubText("子内容子内容子内容子内容子内容")
.setTicker("摘要")//通知显示的内容
.setSmallIcon(R.mipmap.ic_launcher)//设置小图标,4.x在右边,5.x在左边
.setLargeIcon(bitmap)//设置大图标
.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE)//设置默认的呼吸灯和震动
.setContentIntent(pendingIntent)//打开通知后做什么
.setAutoCancel(true);//点击后自动消失

notify(NotificationId, notification);发送通知

3种方式设置灯光+声音+震动

notification.defaults |= Notification.DEFAULT_SOUND;
notification.defaults |= Notification.DEFAULT_VIBRATE;
notification.defaults |= Notification.DEFAULT_LIGHTS;
build.setDefaults(Notification.DEFAULT_ALL)
build.setDefaults(Notification.DEFAULT_SOUND|Notification.DEFAULT_VIBRATE|Notification.DEFAULT_LIGHTS)

关于setVibrate()

vibrate只可以设置一次,用setVibrate()就不可以在用Notification.DEFAULT_VIBRATE,而Notification.DEFAULT_ALL包含DEFAULT_VIBRATE,导致无效setVibrate(pattern)无效

private long[] pattern;
pattern = new long[]{0, 2000, 5000, 2000, 5000, 2000};
builder.setContentTitle("Title")
        .setContentText("message" + getResources().getString(R.string.notification_normal))
        .setSmallIcon(R.mipmap.ic_launcher_round)
        .setTicker("Ticker")
        .setAutoCancel(true)
        .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_LIGHTS)//和setVibrate(pattern)可以同用
//                .setDefaults(Notification.DEFAULT_ALL)//和setVibrate(pattern)不可以同用
        .setVibrate(pattern);

flag:

 public static final int FLAG_SHOW_LIGHTS        = 0x00000001;//控制闪光

 public static final int FLAG_ONGOING_EVENT      = 0x00000002;//将flag设置为这个属性那么通知就会像QQ一样一直在状态栏显示  

 public static final int FLAG_INSISTENT          = 0x00000004; //重复发出声音,直到用户响应此通知 

 public static final int FLAG_ONLY_ALERT_ONCE    = 0x00000008;//标记声音或者震动一次

 public static final int FLAG_AUTO_CANCEL        = 0x00000010; //在通知栏上点击此通知后自动清除此通知 

 public static final int FLAG_NO_CLEAR           = 0x00000020;//将flag设置为这个属性那么通知栏的那个清楚按钮就不会出现

 public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;//前台服务标记

 public static final int FLAG_HIGH_PRIORITY = 0x00000080;

下面通过一个Demo演示通知的使用

https://git.oschina.net/AndroidUI/NotificationDemo.git

MainActivity有2个Button,一个打开通知,一个取消通知。

这里写图片描述

逻辑代码

  protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       btn_open = (Button) findViewById(R.id.btn_open);
       btn_close = (Button) findViewById(R.id.btn_close);

       //打开通知
       btn_open.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               initNotification();
           }
       });

       //关闭通知
       btn_close.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               manager.cancel(NotificationId);//取消通知(根据id)
//                manager.cancelAll();//关闭所有通知
           }
       });
   }

创建通知并设置属性 + 发布通知 + 点击通知跳转到新Activity

//创建通知对象并设置参数
 private void initNotification() {
     //获取 NotificationManager
     manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

     //创建pendingIntent对象
     setPendingIntent();

     //获取bitmap对象
     Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);

     builder = new Notification.Builder(this);
     builder.setContentTitle("标题")
             .setContentText("内容内容内容内容内容内容内容")
             .setSubText("子内容子内容子内容子内容子内容")
             .setTicker("摘要")//通知显示的内容
             .setSmallIcon(R.mipmap.ic_launcher)//设置小图标,4.x在右边,5.x在左边
             .setLargeIcon(bitmap)//设置大图标
             .setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND)//设置默认的呼吸灯+震动+声音
             .setContentIntent(pendingIntent)//打开通知后做什么
             .setAutoCancel(true);//点击后自动消失

     notification = builder.build();
     notification.flags |= Notification.FLAG_INSISTENT;//不查看通知就一直发出声音和震动
     //发布通知
     manager.notify(NotificationId, notification);
 }

自定义震动时长:

long[] vibrates={0,1000,1000,1000,1000,1000};
notification.vibrate = vibrates;

震动+铃声+闪光:

notification.defaults = Notification.DEFAULT_ALL

获取PendingIntent

private void setPendingIntent() {
       Intent intent = new Intent(this, NewActivity.class);
       intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
       pendingIntent = PendingIntent.getActivity(this, 1, intent, 0);
   }

Ticker:
这里写图片描述
ContentTitle + ContentText + SubText + LargeIcon + SmallIcon
这里写图片描述

自定义通知布局

guilde:https://developer.android.google.cn/guide/topics/ui/notifiers/notifications.html#CustomNotification
sample:https://developer.android.google.cn/samples/CustomNotifications/index.html

效果图

这里写图片描述 这里写图片描述

方法

builder方法说明
setContent(contentView)添加自定义布局:高度4行文字
setCustomContentView(contentView)添加自定义布局:高度4行文字
添加自定义布局:高度4行文字
setCustomBigContentView(bigContentView)高度最大,全部显示

自定义通知布局是通过RemoteViews实现的,

有2种方法添加自定义布局

第一种:已经过时

notification.contentView = contentView;
notification.bigContentView = bigContentView;

第二种:builder

builder.setContent(contentView)
builder.setCustomContentView(contentView)
builder.setCustomBigContentView(bigContentView)

notification.contentView

NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setContentTitle("Title")
        .setContentText("message")
        .setSmallIcon(R.mipmap.ic_launcher_round)
        .setTicker("ticker")
        .setAutoCancel(true)
        .setSmallIcon(R.mipmap.ic_launcher_round);
Notification notification = builder.build();

//自定义contentView
RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.notification_normal);
contentView.setTextViewText(R.id.tv_normal, getResources().getString(R.string.notification_normal));
notification.contentView = contentView;

//自定义bigContentView
if (Build.VERSION.SDK_INT >= 16) {
    RemoteViews bigContentView = new RemoteViews(getPackageName(), R.layout.notification_enpanded);
    bigContentView.setTextViewText(R.id.tv_expanded, getResources().getString(R.string.notigication_expanded));
    notification.bigContentView = bigContentView;
}

NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.notify(0, notification);

builder.setCustomContentView(view)builder.setCustomBigContentView(view)

RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.notification_normal);
contentView.setTextViewText(R.id.tv_normal, getResources().getString(R.string.notification_normal));

RemoteViews bigContentView = new RemoteViews(getPackageName(), R.layout.notification_enpanded);
bigContentView.setTextViewText(R.id.tv_expanded, getResources().getString(R.string.notigication_expanded));

RemoteViews headerContentView = new RemoteViews(getPackageName(), R.layout.notification__header_up);
bigContentView.setTextViewText(R.id.tv_header, "Header");

NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setContentTitle("Title")//占用一行
        .setContentText("message")//占用一行
        .setSmallIcon(R.mipmap.ic_launcher_round)
        .setTicker("Ticker")
        .setAutoCancel(true)
        .setDefaults(Notification.DEFAULT_ALL)
        .setContent(contentView)//效果和setCustomContentView一样,同样是占用4行,
        .setCustomContentView(contentView)//占用4.setCustomBigContentView(bigContentView)//最大
//                .setCustomHeadsUpContentView(headerContentView)//无效
;
Notification notification = builder.build();

NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.notify(0, notification);

把service设置成前台进程

把service设置成前台进程:

Notification notification = new Notification.Builder(this).build();
startForeground(1, notification);

把service的前台进程销毁:

stopForeground(true);

这里写图片描述

浮动通知

这里写图片描述
让通知直接浮动显示,而不是需要下滑通知栏才显示。有2种方法
- 提交Notification的优先级为Notification.PRIORITY_HIGH或者Notification.PRIORITY_MAX,并使用了震动或铃声
- 用户的 Activity 处于全屏模式中(应用使用 fullScreenIntent

方式一: 通告优先级

builder.setPriority(Notification.PRIORITY_HIGH)
builder.setPriority(Notification.PRIORITY_MAX)

builder.setDefaults(Notification.DEFAULT_ALL)

方式二:使用fullScreenIntent

Intent intent = new Intent(context, NewActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

builder.setFullScreenIntent(pendingIntent, false);//第2个参数:是否是高优先级

Inbox扩展布局

这里写图片描述
相当于在通知中加入了ListView,但是没有点击事件

NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
inboxStyle.setBigContentTitle("BigContentTitle:");
for (int i = 0; i < 6; i++) {
    inboxStyle.addLine("item  " + i);
}

build..setStyle(inboxStyle);

启动Activity时保留导航

就是在MainActivity中发送Notification,点击开启NewActivity,当关闭NewActivity后,会回到MainActivity
根据activity分2种实现方式:
- 常规Activity
- 特殊Activity

那么到底是什么意思呢?我们知道从Notification打开Activity_A,必须给Activity_A设置android:launchMode="singleTask"intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);,但是这个Activity_A只可以在通知种打开,在其他Activity中无法启动它,我们把Activity_A成为特殊的Activity,这个Activity_A不是工作流的一部分,可以让它既可以从通知中打开Activity_A,也可以在其他Activity中打开,这是可以的,这种就是常规Activity

常规Activity

第一步:在AndroidManifest.xml中定义NewActivity的层级结构

首先在AndroidManifest.xml中定义NewActivity的层级结构,对于Android4.1只需要设置parentActivityName即可,值是父Activityandroid:name=".MainActivity"name的值,对于老版本,还需要添加meta-data

<activity
    android:name=".NewActivity"
    android:parentActivityName=".MainActivity">
    <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value=".MainActivity"/>
</activity>

添加android:parentActivityName属性的目的是:当我们点击通知,打开Activity_A,,当关闭A时,系统会启动该属性对应的Activity(例如MainActivity)。那么问题来了,为什么不直接使用startActivty(…),因为如果当前页就是MainActivity,点击通知打开A,在关闭A,启动MainActivity,加上原来的MainActivity就有2个了,必须finish()2次才可以关闭掉MainActivity。

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

Intent intent = new Intent(context, NewActivity.class);
TaskStackBuilder builder = TaskStackBuilder.create(context)
         .addParentStack(NewActivity.class)
         .addNextIntent(intent);
PendingIntent pendingIntent = builder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
build.setContentIntent(pendingIntent)

注意:必须先设置父堆栈,再设置intent,顺序不可错。

TaskStackBuilder builder = TaskStackBuilder.create(context)
        .addParentStack(NotificationInfoActivity.class)
        .addNextIntent(intent);

特殊Activity

第一步:在清单文件中,将以下属性添加到 Activity 的 元素

<activity
    android:name=".NewActivity2"
    android:excludeFromRecents="true"
    android:launchMode="singleTask"
    android:taskAffinity=""/>

android:excludeFromRecents="true"确保点击通知打开NewActivity2时不会销毁MainActivity

第二步:构建并发出通知

Intent intent = new Intent(context, NewActivity2.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
build.setContentIntent(pendingIntent)

可以在关闭NotificationInfoActivity时启动MAinActivity吗?

不可以,因为如果当前页是MainActivity,此时点击Notification,打开NotificationInfoActivity,关闭NotificationInfoActivity时,我们启动MAinActivity,这样会有2个MAinActivity示例,点击back键一次就之关闭一个MAinActivity,点击2次,才可以全部关闭。

显示进度

分2种:
- 有固定时长的进度显示
- 无固定时长的进度显示

是通过build.setProgress (int max, int progress, boolean indeterminate)实现的。setProgress(0, 0, false)清除通知中的progressbar

第一个参数:最大值
第二个参数:当前值
第三个参数:true:不确定时长;false:确定时长

时长不固定

这里写图片描述

final Notification.Builder builder = new Notification.Builder(context);

builder.setContentTitle("在通知中显示进度一:显示持续 Activity指示器")
        .setContentText("message" + getResources().getString(R.string.notification_normal))
        .setSmallIcon(R.mipmap.ic_launcher_round)
        .setTicker("Ticker")
        .setAutoCancel(true)
        .setProgress(0, 0, true)
        .setDefaults(Notification.DEFAULT_ALL);
final NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

new Thread(new Runnable() {
    @Override
    public void run() {
        for (int i = 0; i <= 30; i += 5) {
            builder.setProgress(0, 0, true);
            manager.notify(1, builder.build());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        builder.setContentText("下载完成").setProgress(0, 0, true);//移除通知
        manager.notify(7, builder.build());
    }
}).start();

时长固定

这里写图片描述

final Notification.Builder builder = new Notification.Builder(context);

builder.setContentTitle("在通知中显示进度二:显示持续时间固定的进度指示器")
        .setContentText("message" + getResources().getString(R.string.notification_normal))
        .setSmallIcon(R.mipmap.ic_launcher_round)
        .setTicker("Ticker")
        .setAutoCancel(true)
        .setProgress(100, 0, false)
        .setDefaults(Notification.DEFAULT_ALL);
final NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

new Thread(new Runnable() {
    @Override
    public void run() {
        for (int i = 0; i <= 20; i += 5) {
            builder.setProgress(100, i, false);
            manager.notify(8, builder.build());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        builder.setContentText("下载完成").setProgress(0, 0, false);//移除通知
        manager.notify(8, builder.build());
    }
}).start();

锁屏显示

这里写图片描述
类似于壁纸,API>=21

build.setVisibility(Notification.VISIBILITY_PUBLIC)

您的应用可以控制在安全锁定屏幕上显示的通知中可见的详细级别。 调用 setVisibility() 并指定以下值之一:

VISIBILITY_PUBLIC: 显示通知的完整内容。
VISIBILITY_SECRET: 不会在锁定屏幕上显示此通知的任何部分。
VISIBILITY_PRIVATE: 显示通知图标和内容标题等基本信息,但是隐藏通知的完整内容。

flag:Notification.FLAG_INSISTEN一直提醒

第一次:声音+震动,之后只有声音,不可以与Notification.DEFAULT_ALL共用

build.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE)
notification.flags |= Notification.FLAG_INSISTENT;

demo:

Notification.Builder builder = new Notification.Builder(context);

builder.setContentTitle("一直有声音+震动+呼吸灯")
        .setContentText("message" + getResources().getString(R.string.notification_normal))
        .setSmallIcon(R.mipmap.ic_launcher_round)
        .setTicker("Ticker")
        .setAutoCancel(true)
        .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE)
        .setPriority(Notification.PRIORITY_DEFAULT);
Notification notification = builder.build();
notification.flags |= Notification.FLAG_INSISTENT;
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.notify(13, notification);

bug

1 点击通知,开启的activity是空白页,但是我们设置的activity是有内容的,这是为什么呢?

原因:重写的onCreate(…)方法有2种:第一种:用protected修饰,且只有1个参数:Bundle;第二种:用public修饰,且有2个参数:Bundle + PersistableBundle,第一种是正确的。

这里写图片描述

有的博客说到:
Android中notification点击进入新activity,会打开多个相同activity,需要在Intent设置如下flag :intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
这种情况我还没遇到。

nm.notify()无效

一定要设置smallIcon(),不然notification不会显示。

setSmallIcon(R.mipmap.logo)

源码下载:https://github.com/s1168805219/NotificationDemo

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值