1.概述
当应用程序在后台运行,希望向用户发出一些提示学习,就需要借助Notification(通知)来实现。在发出一条通知后,手机最上方的状态栏会显示一个通知的图标,下拉状态栏后就可以看到通知的详细内容。
1.1 视图分类
Notification有两种视觉风格,一种是标准视图(Normal View),另外一种是大视图(Big view)。标准视图在Android中各版本是通用的,但是对于大视图而言,仅支持Android4.1+的版本。
1.2 标准视图
从官方文档了解到,一个标准视图显示的大小保持在64dp高。如下图所示:
其属性描述如下:
1代表:通知标题
2代表:大图标
3代表: 通知内容
4代表:通知消息
5代表:小图标
6代表:通知时间,一般为系统时间,也可以使用setWhen()设置。
1.3 大视图
对于大视图(Big View)而言,它的细节区域只能显示256dp高度的内容,并且只对Android4.1+之后的设备才支持,它比标准视图不一样的地方,均需要使用setStyle()方法设定,它大致的效果如下:
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;
--------------------------------
原文:/dsc114/article/details/51721472
2.基本用法
通知可以在活动里面创建,也可以在广播接收器里面创建,也可以在服务里面创建。下面介绍创建通知的步骤:
2.1 创建一个NotificationManager
创建一个NotificationManager来对通知进行管理。通过调用Context.getSystemService(String s)方法获取到NotificationManager实例对象,字符串s参数用于确定获取系统的哪个服务,这里传入Context.NOTIFICATION_SERVICE即可,如下所示:
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
其中,Context.NOTIFICATION_SERVICE的值为:notification
public abstract class Context {......public static final String NOTIFICATION_SERVICE = "notification";}
2.2 使用Builder构造器来创建Notification对象
在这里需要注意的是,为了解决API不稳定性问题和新老版本的兼容问题,使用support-v4提供的NotificationCompat类的Builder构造器来创建Notification对象,可以保证程序在所有的版本上都能正常工作。同时,Android8.0开始,废弃了Builder(@NonNullContext context)方法,改用public Builder(@NonNull Context context, @NonNull String channelId),如下所示:
//创建Notification,传入Context和channelIdNotification notification = new NotificationCompat.Builder(this, "chat").setAutoCancel(true).setContentTitle("收到聊天消息").setContentText("今天晚上吃什么").setWhen(System.currentTimeMillis()).setSmallIcon(R.mipmap.ic_launcher).setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)).setContentIntent(pendingIntent)//在build()方法之前还可以添加其他方法.build();
Builder构造器其中一些方法说明如下:
其中setPriority(int pri)方法参数一共有5个常量值可选,调用NotificationCompat的常量值,如下所示:
public class NotificationCompat {.......//默认的重要程度,和不设置效果是一样的public static final int PRIORITY_DEFAULT = 0;//最低的重要程度,系统可能只会在特定的场合显示这条通知public static final int PRIORITY_MIN = -2;//较低的重要程度,系统可能会将这类通知缩小,或改变其显示的顺序public static final int PRIORITY_LOW = -1;//较高的重要程度,系统可能会将这类通知放大,或改变其显示的顺序public static final int PRIORITY_HIGH = 1;//最高的重要程度,表示这类通知消息必须让用户看到,甚至做出响应public static final int PRIORITY_MAX = 2;}
注意:当设置最高重要程度后,其显示效果和QQ发送好友消息一样,如果正在其他APP内,消息会显示在屏幕上让用户看见
2.3 调用NotificationManager的notify(int id, Notification notification)让通知显示
notify()方法接收两个参数,其中id表示每个通知所指定的id,要不一样。代码如下:
notificationManager.notify(1, notification);
使用此方法前,需要将NotificationChannel(通知渠道创建出来)
2.4 让通知从状态栏消失方法
有两种方法,一种是上面创建Notification时,添加setAutoCancel(true),另外一种就是通过动态代码方式,NotificationManager.cancel(int id),如下:
//传入对应通知的idnotificationManager.cancel(1);
3.NotificationChannel(通知渠道)
3.1 概述
从Android 8.0系统开始,Google引入了通知渠道这个概念。
什么是通知渠道呢?顾名思义,就是每条通知都要属于一个对应的渠道。每个App都可以自由地创建当前App拥有哪些通知渠道,但是这些通知渠道的控制权都是掌握在用户手上的。用户可以自由地选择这些通知渠道的重要程度,是否响铃、是否振动、或者是否要关闭这个渠道的通知。
即NotificationChannel
其实是把Notification
分了个类别,设置不同优先级,开关之类的。如果你的 app 适配了的话,用户可以关掉不喜欢的通知,以提高用户体验。拥有了这些控制权之后,用户就再也不用害怕那些垃圾推送消息的打扰了,因为用户可以自主地选择自己关心哪些通知、不关心哪些通知。举个具体的例子,我希望可以即时收到支付宝的收款信息,因为我不想错过任何一笔收益,但是我又不想收到支付宝给我推荐的周围美食,因为我没钱只吃得起公司食堂。这种情况,支付宝就可以创建两种通知渠道,一个收支,一个推荐,而我作为用户对推荐类的通知不感兴趣,那么我就可以直接将推荐通知渠道关闭,这样既不影响我关心的通知,又不会让那些我不关心的通知来打扰我了。
对于每个App来说,通知渠道的划分是非常需要仔细考究的,因为通知渠道一旦创建之后就不能再修改了,因此开发者需要仔细分析自己的App一共有哪些类型的通知,然后再去创建相应的通知渠道。
这里我们来参考一下Twitter的通知渠道划分,如下所示:
可以看到,Twitter就是根据自己的通知类型,对通知渠道进行了非常详细的划分,这样用户的自主选择性就比较高了,也就大大降低了用户不堪其垃圾通知的骚扰而将App卸载的概率。
---------------------
原文:/guolin_blog/article/details/79854070
3.2 创建NotificationChannel
代码如下所示:
public class NotificationUtil {private static final int NOTIFICATION_MUSIC_ID = 10000;private static NotificationManager notificationManager;......//初始化NotificationManagerprivate static void initNotificationManager(Context context){if (notificationManager == null){notificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);}//判断是否为8.0以上:Build.VERSION_CODES.O为26if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//创建通知渠道IDString channelId = "musicNotification";//创建通知渠道名称String channelName = "音乐播放器通知栏";//创建通知渠道重要性int importance = NotificationManager.IMPORTANCE_DEFAULT;createNotificationChannel(context, channelId, channelName, importance);}}//创建通知渠道@TargetApi(Build.VERSION_CODES.O)private static void createNotificationChannel(Context context, String channelId, String channelName, int importance) {NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);//channel有很多set方法......//为NotificationManager设置通知渠道notificationManager.createNotificationChannel(channel);}}
说明:这里传入的channelId要和创建的通知channelId一致,才能为指定通知建立通知渠道
1)NotificationChannel的方法列表
2)重要程度
数值越高,提示权限就越高,最高的支持发出声音和悬浮通知,如下所示:
public class NotificationManager {......public static final int IMPORTANCE_DEFAULT = 3;public static final int IMPORTANCE_HIGH = 4;public static final int IMPORTANCE_LOW = 2;public static final int IMPORTANCE_MAX = 5;public static final int IMPORTANCE_MIN = 1;public static final int IMPORTANCE_NONE = 0;public static final int IMPORTANCE_UNSPECIFIED = -1000;}
3)发出通知
调用NotificationManager的notify()方法即可
4)删除NotificationChann
调用NotificationManager的deleteNotificationChannel(int chatChannelId)即可。
4.案例
1)xml布局
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"android:orientation="vertical"><Buttonandroid:id="@+id/chat"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="发送聊天通知"/></LinearLayout>
2)代码
public class MainActivity extends AppCompatActivity implements View.OnClickListener{private NotificationManager manager;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {String channelId = "chat";String channelName = "聊天消息";int importance = NotificationManager.IMPORTANCE_HIGH;createNotificationChannel(channelId, channelName, importance);channelId = "subscribe";channelName = "订阅消息";importance = NotificationManager.IMPORTANCE_DEFAULT;createNotificationChannel(channelId, channelName, importance);}Button chat = findViewById(R.id.chat);chat.setOnClickListener(this);Button get = findViewById(R.id.get);get.setOnClickListener(this);}@TargetApi(Build.VERSION_CODES.O)private void createNotificationChannel(String channelId, String channelName, int importance) {NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);notificationManager.createNotificationChannel(channel);}@Overridepublic void onClick(View view) {switch (view.getId()){case R.id.chat: //聊天消息Notification notification = new NotificationCompat.Builder(this, "chat").setAutoCancel(true).setContentTitle("收到聊天消息").setContentText("今天晚上吃什么").setWhen(System.currentTimeMillis()).setSmallIcon(R.mipmap.ic_launcher)//设置红色.setColor(Color.parseColor("#F00606")).setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)).setContentIntent(pendingIntent).build();manager.notify(1, notification);break;case R.id.get: //订阅消息Notification notificationGet = new NotificationCompat.Builder(this, "subscribe").setAutoCancel(true).setContentTitle("收到订阅消息").setContentText("新闻消息").setWhen(System.currentTimeMillis()).setSmallIcon(R.mipmap.ic_launcher).setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)).setContentIntent(pendingIntentGet).build();manager.notify(2, notificationGet);break;}}}
3)效果
注意这里出现了大图标和小图标,聊天消息之所以是红色,因为setColor为红色,详情见:
/guolin_blog/article/details/50945228
5.使用RemoteViews自定义Notification
需要使用RemoteViews.RemoteViews描述了一个视图层次的结构,可以显示在另一个进程。
RemoteViews提供了多个构造函数,一般使用RemoteViews(String packageName,int layoutId)。第一个参数为包的名称,第二个为layout资源的Id。当获取到RemoteViews对象之后,可以使用它的一系列setXxx()方法通过控件的Id设置控件的属性。最后使用NotificationCompat.Builder.setContent(RemoteViews)方法设置它到一个Notification中。
6.PendingIntent
6.1 概述
对于一个通知而言,它显示的消息是有限的,一般仅用于提示一些概要信息。但是一般简短的消息,并不能表达需要告诉用户的全部内容,所以需要绑定一个意图,当用户点击通知的时候,调用一个意图展示出一个Activity用来显示详细的内容。而Notification中,并不使用常规的Intent去传递一个意图,而是使用PendingIntent。
Intent和PendingIntent的区别:PendingIntent可以看做是对Intent的包装,通过名称可以看出PendingIntent用于处理即将发生的意图,而Intent用来用来处理马上发生的意图。而对于通知来说,它是一系统级的全局通知,并不确定这个意图被执行的时间。当在应用外部执行PendingIntent时,因为它保存了触发应用的Context,使得外部应用可以如在当前应用中一样,执行PendingIntent里的Intent,就算执行的时候响应通知的应用已经被销毁了,也可以通过存在PendingIntent里的Context照常执行它,并且还可以处理Intent说带来的额外信息。
因此可以将PendingIntent看做是延迟执行的Intent。
6.2 创建PendingIntent
获取PendingInten实例可以根据需求从如下方法中获取:
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属性参数用于确定PendingIntent的行为:FLAG_ONE_SHOT: 表示返回的PendingIntent仅能执行一次,执行完后自动消失FLAG_NO_CREATE: 表示如果描述的PendingIntent不存在,并不创建相应的PendingIntent,而是返回NULLFLAG_CANCEL_CURRENT: 表示相应的PendingIntent已经存在,则取消前者,然后创建新的PendingIntentFLAG_UPDATE_CURRENT: 表示更新的PendingIntent,如果构建的PendingIntent已经存在,则替换它,常用。
获取到PendingIntent实例后,通过Builder构造器的setContentIntent(PendingIntent intent)方法,构建一个PendingIntent。
---------------------
原文:/dsc114/article/details/51721472
6.3 使用案例
这里对目录4案例的代码进行改造,在代码中添加如下方法:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{private NotificationManager manager;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);......}@TargetApi(Build.VERSION_CODES.O)private void createNotificationChannel(String channelId, String channelName, int importance) {......}@Overridepublic void onClick(View view) {switch (view.getId()){case R.id.chat:Intent intent = new Intent(this, NotificationActivity.class);PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);Notification notification = new NotificationCompat.Builder(this, "chat").......setContentIntent(pendingIntent).build();manager.notify(1, notification);break;case R.id.get:Intent intentGet = new Intent(this, NotificationActivity.class);PendingIntent pendingIntentGet = PendingIntent.getActivity(this, 0, intentGet, 0);Notification notificationGet = new NotificationCompat.Builder(this, "subscribe").......setContentIntent(pendingIntentGet).build();manager.notify(2, notificationGet);break;}}}
点击通知消息后,就可以跳转到NotificationActivity对应的界面了