Notification,是一种具有全局效果的通知,可以在系统的通知栏中显示。当 APP 向系统发出通知时,它将先以图标的形式显示在通知栏中。用户可以下拉通知栏查看通知的详细信息。
android 通知的四种形式: 普通通知 悬挂式通知 折叠式通知 锁屏通知
但是先在推出了安卓8.0的系统过后,普通的通知不能在通知栏直接实现,需要一个适配--通知渠道
需要适配的原因:现在的APP通知争相吃醋,自由发送通知杂乱无章让通知栏饱受折磨,因此为了让用户对感兴趣和不感兴趣的通知进行区分。好比我们想得知淘宝快递和喜欢货品降价通知却不想要无关衣物推荐之类的通知。在安卓8.0之前就只能把淘宝通知全开着或者全关掉。(任意一个都是艰难的决定)
那么在Android8.0系统中,Google也是从这个痛点下手。
8.0系统的通知区分:
从Android8.0之后,Google引入通知渠道----每个通知对应一个渠道。
每个app都能创建当前app拥有哪些渠道,但这些渠道的控制权在用户手上。用户可以自由选择这些通知渠道的重要程度,是否响铃,是否振动啊之类的。
直接上图
这是我自己写的三类通知划分,用户的自主选择性就更好了。
在此引用郭霖的一段来介绍适配的必要性:
Google这次对于8.0系统通知渠道的推广态度还是比较强硬的。
首先,如果你升级了appcompat库,那么所有使用appcompat库来构建通知的地方全部都会进行废弃方法提示,如下所示:
上图告诉我们,此方法已废弃,需要使用带有通知渠道的方法才行。
当然,Google也并没有完全做绝,即使方法标为了废弃,但还是可以正常使用的。可是如果你将项目中的targetSdkVersion指定到了26或者更高,那么Android系统就会认为你的App已经做好了8.0系统的适配工作,当然包括了通知栏的适配。这个时候如果还不使用通知渠道的话,那么你的App的通知将完全无法弹出。因此这里给大家的建议就是,一定要适配。
那就让我们来看看如何适配的吧!
首先用AS创建项目查看build.gradle中targetSdkVersion版本,确认在26即以上如下所示:
来到MainActivity中可以像我这样每一次调用都写一遍通道:
NotificationChannel b;
NotificationCompat.Builder mBuilder3 = new NotificationCompat.Builder(this);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
b = new NotificationChannel("689","乱七八糟的其他信息", NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(b);
mBuilder3.setChannelId("689");
}
首先对手机版本进行判断,为android8.0以上的添加通知渠道:之中id即ChannelId与mBuilder中setChannelId(ChannelId)相同才可正常进行通知 name为通知渠道名称 NotificationManager.IMPORTANCE_HIGH为通知重要程度不同程度可由用户在手机上自行设置
其中
//用appcompat库的Builder创造了mbuilder这个实例,后文会讲mbuilder这个对象的作用
NotificationCompat.Builder mBuilder3 = new NotificationCompat.Builder(context: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);
}
对于Android 8.0 以后的通知渠道就到这。还有些功能具体看郭霖微信吧。 郭霖对android 8.0系统的通知栏适配
下面我们开始讲讲通知该怎么个写法呢?
以下内容基本适用于android版本低于8.0 因为高于8.0过后消息格式全部能调比如悬挂式为重要程度为紧急即可。
我设置了三个按钮分别对应三种通知
三种通知第一步都是实例化NotificationManager:(所以我设置了一个全局化的实例)
NotificationManager 对通知进行管理,调用 Context 的 getSystemService() 方法获取。
代码:
public class MainActivity extends AppCompatActivity {
//全局
private NotificationManager notificationManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*
* 创造通知栏管理工具
*/
notificationManager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
//设置的三个通知对应的三个Button
Button button = findViewById(R.id.main_but1);
Button button1 = findViewById(R.id.main_but2);
Button button2 = findViewById(R.id.main_but3);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
but_common_notification();
}
});
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
but_zhedie_notification();
}
});
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
but_hang_notification();
}
});
}
首先介绍的是普通通知:
Android在appcompat-v7库中提供了一个NotificationCompat类来处理新老版本的兼容问题,我们在编写通知功能时都使用NotificationCompat这个类来实现,appcompat-v7库就会自动帮我们做好所有系统版本的兼容性处理了。
所以我们通过appcompat来创建一个Builder对象通过PendingIntent来实现通知跳转,通过Builder的.set方法来给通知添加属性 考虑到之前说的Android 8.0 版本之后所以完整代码加了通知渠道。
在此之前我们下来了解了解PendingIntent和Intent的区别:
Intent 是及时启动,intent 随所在的activity 消失而消失。
PendingIntent 可以看作是对intent的包装,通常通过getActivity,getBroadcast,getService来得到pendingintent的实例,当前activity并不能马上启动它所包含的intent,而是在外部执行 pendingintent 时,调用intent的。正由于pendingintent中保存有当前App的Context,使它赋予外部App一种能力,使得外部App可以如同当前App一样的执行pendingintent里的 Intent, 就算在执行时当前App已经不存在了,也能通过存在pendingintent里的Context照样执行Intent。
pendingIntent对象,使用方法类的静态方法 :
getActivity(Context, int, Intent, int)------->跳转到一个activity组件、
getBroadcast(Context, int, Intent, int)------>打开一个广播组件
getService(Context, int, Intent, int)-------->打开一个服务组件。
分别对应着Intent的3个行为和参数有4个,比较重要的事第三个和第一个,其次是第四个和第二个。可以看到,要得到这个对象,必须传入一个Intent作为参数,必须有context作为参数。其中第二个为requestcode一般为0,第四个为flags
private void but_common_notification() {
/*
* 实例化通知栏构造器
*/
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
/*
设置Builder
*/
//设置通知消息的跳转 --> Intend 和PendingIntent 的使用
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.jianshu.com/u/5be2f82148ce"));
PendingIntent pendingIntent =PendingIntent.getActivity(this,0,intent,0);
//
NotificationChannel a;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
a = new NotificationChannel("10086","喜欢物品降价通知", NotificationManager.IMPORTANCE_LOW);
notificationManager.createNotificationChannel(a);
mBuilder.setChannelId("10086");
}
mBuilder.setContentTitle("通知标题")
.setContentText("通知内容")
.setContentIntent(pendingIntent) //传入PendingIntent的实例即可
//大图标
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
//小图标
.setSmallIcon(R.mipmap.ic_launcher_round)
// .setVisibility(Notification.VISIBILITY_PUBLIC)
//首次进入显示的效果
//.setTicker("测试内容")
//设置提醒的模式
.setDefaults(Notification.DEFAULT_SOUND);
//最后通过nitificationManager.notify将通知发送出去即实现了将通知加入状态栏,标记为id
// notify中两个参数为 第一个id参数说明:id相当于notification的一一对应标志
//notify的第一个参数是常量的话,那么多次notify只能弹出一个通知,后续的通知会替换掉原有通知
// 而如果每次id不同,那么多次调用notify会弹出多个通知
notificationManager.notify(1,mBuilder.build());
}
运行效果预览
折叠式通知:
感觉期望的作用就是自定义通知。自己写xml文件满足个性化需求。(但所允许的布局是有限的:FrameLayout LinearLayout RelativeLayout GridLayout)还有view也是有限的这个自己去了解吧。
大部分内容同普通通知一致,但折叠通知采用了RemoteViews。
RemoteViews在实际开发过程中,多用于通知栏和桌面小部件。他们用到RemoteViews的原因在于,二者在更新界面的时候无法像在Acitivity里面那样去更新View,这是因为二者的界面都运行在其他进程中,确切的说是系统的SystemServer进程。为了跨进程跟新界面,RmoteViews提供了一系列set方法。
自定义通知的效果需要用到RemoteViews效果如下图。
RemoteVIews的使用:只要提供当前应用的包名和布局文件的资源id即可创建一个RemoteViews对象
更新RemoteViews:无法直接访问View,可通过RemoteViews提供方法例如:TextView文本:remoteViews.setTextViewText(R.id.not_text,"surprise"); ImageView: remoteViews.setImageResourse(R.id.scoller_image,R.drawable.image);
更新完后添加到mBuilder里边去。
完整代码如下:
private void but_zhedie_notification() {
Intent intent = new Intent(Intent.ACTION_VIEW,Uri.parse("https://www.jianshu.com/u/5be2f82148ce"));
PendingIntent pendingIntent =PendingIntent.getActivity(this,0,intent,0);
NotificationChannel b;
NotificationCompat.Builder mBuilder2 = new NotificationCompat.Builder(this);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
b = new NotificationChannel("6890","货流信息", NotificationManager.IMPORTANCE_LOW);
notificationManager.createNotificationChannel(b);
mBuilder2.setChannelId("6890");
}
//下拉时的样式
RemoteViews show = new RemoteViews(getPackageName(),R.layout.notification_scoller);
show.setTextViewText(R.id.not_text,"surprise");
show.setImageViewResource(R.id.scoller_image,R.drawable.image);
//未下拉的样式
RemoteViews collapsed = new RemoteViews(getPackageName(),R.layout.notification_show);
mBuilder2.setAutoCancel(true)
.setSmallIcon(R.mipmap.ic_launcher_round)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
.setContentTitle("折叠式")
.setCustomContentView(collapsed)
.setCustomBigContentView(show)
.setContentIntent(pendingIntent);
notificationManager.notify(0,mBuilder2.build());
}
悬挂式
基本同普通通知若是Android 8.0 以后版本仅需要在通知渠道处的importance处把重要等级调至IMPORTANCE_HIGH 即可实现悬挂通知。
也可以让用户直接在手机上设置通知的重要等级。紧急即可实现悬挂。
NotificationChannel b;
NotificationCompat.Builder mBuilder3 = new NotificationCompat.Builder(this);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
//最后的importance修改一下就行了。
b = new NotificationChannel("689","乱七八糟的其他信息", NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(b);
mBuilder3.setChannelId("689");
}
实现效果如下:若是Android 8.0之前的版本在mBuilder里边添加setFullScreenIntent调用
mBuilder.setFullScreenIntent(PendingIntent,true);
或者启动声音提示和振动提示
锁屏通知
锁屏通知
Android 5.0(API level 21)开始,通知可以显示在锁屏上。用户可以通过设置选择是否允许敏感的通知内容显示在安全的锁屏上。可以通过setVisibility()控制通知的显示等级:
VISIBILITY_PRIVATE : 显示基本信息,如通知的图标,但隐藏通知的全部内容
VISIBILITY_PUBLIC : 显示通知的全部内容
VISIBILITY_SECRET : 不显示任何内容,包括图标
最后有个通知栏小技巧 针对android 5.0以上通知栏小图标问题参考博客