Android 消息通知栏用法详解(二) 适配8.0
通知(Notification) 是Android 系统比较有特色的一个功能,当某个应用程序希望向用户发出一些提示信息的时,而该应用程序又处于后台,就可以借助通知来实现。比如微信弹窗。通过这篇文章,我们将学习到
官网 Nitification 资料
通知可以在 广播、activity 或者 service 去创建,不过在 activity 创建得比较少,一般都是应用在后台了,才需要去弄,不过我们是demo,所以写哪都没关系。
创建通知的基本步骤如下:
上面中,为什么要使用 NotificationCompat 呢,因为Android系统的每一个版本都会对通知这部分功能进行或多或少的修改,API 比较不稳定,所以这里使用 v4 的包去兼容,当然,如果你使用 androidx,也就没啥问题了。
所以,一个简单的通知实例如下 :
以下代码建议在8.0之下运行,8.0以上,请参考下一篇文章
首先创建 NotificationManager
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this)
.setContentTitle("这是标题")
.setContentText("我是内容,我是demo")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher));
//通过 builder.build() 拿到 notification
mNotificationManager.notify(1, mBuilder.build());
解释如下:
都设置完成之后,只要使用 nofity() 即可,其中,第一个参数为 id,后面用来取消通知的。所以随便填一个数字即可,效果如下。
可以看到,小图标是灰色的。当然了,google 要求是 alpha 的图层呢。
什么是 纯 alpha 的图层图片呢?通俗来讲,就是图片不要带颜色就可以了,当然UI设计师肯定知道,就是用 alpha 层去绘制图片吗,咱们也可以从 阿里巴巴的图片库下载,比如:
然后咱们设置一下
但是,发现默认还是灰色的,这里可以使用 setcolor 去设置:
.setColor(getResources().getColor(R.color.colorPrimary))
一般的通知栏都是可以点击的,但是我们点击了一下,发现并没有什么用。当然,我们都没设置点击事件。
notification 的点击事件,可以通过设置 setContentIntent 来实现。它需要传递一个 PendingIntent。从而实现点击之后的跳转意图。
PendingIntent 的用法也很简单,它可以通过 getActivity(),getBroadcast() 和 getService() 来获取不同的实例,一个简单获取 activity 的方法如下:
Intent intent = new Intent(this,SecondActivity.class);
PendingIntent pi = PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_CANCEL_CURRENT);
它的参数也比较简单,第一个为 context,第二个为 requestCode,一般用不到,intent 即你要跳转的意图。第四个参数有5种选择,分别如下:
一般第四个传输,传递 0 或者FLAG_CANCEL_CURRENT 都可以。
所以,我们的通知代码改一下:
mBuilder = new NotificationCompat.Builder(this)
.setContentTitle("这是标题")
.setContentText("我是内容,我是demo")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
.setContentIntent(pi);
//通过 builder.build() 拿到 notification
mNotificationManager.notify(1, mBuilder.build());
点击之后,发现确实跳转了,但是通知栏还在。取消共有两种方式
更新通知,只需要重新 notify 相同的 id 即可,如果通知栏还在,则更新内容,如果不存在,则增加一个新的通知栏,如下,我们更新一下内容:
mBuilder.setContentText("我更新了内容");
mNotificationManager.notify(1,mBuilder.build());
上面,咱们只是简单的实现了通知栏,但是一些好玩的效果,咱们并没有实现,这节,一起来看看通知栏的效果。
(请用真机测试)
很多通知栏,都有声音的效果,同样,我们也可以设置。使用 setSound 即可实现,比如:
mBuilder = new NotificationCompat.Builder(this)
...
//这个看各自的手机的铃声的路径
.setSound(Uri.fromFile(new File("system/media/audio/notifications/Argon.ogg")))
.setAutoCancel(true);
除了自定义,还可以使用默认铃声:
.setDefaults(NotificationCompat.DEFAULT_SOUND)
除了声音,还可以让手机震动,使用的是 setVibrate,它的参数为一个 long 的数组,以 ms 为单位,如果我们想让手机震动1s,延时一秒,再震动一次,当然,它需要向申请权限
.setVibrate(new long[]{0,1000,1000,1000})
同理,也可以使用默认震动效果:
.setDefaults(NotificationCompat.DEFAULT_VIBRATE)
现在手机都LED灯,在手机息屏或者未接来电灯,还是还有必要的。同样,可以使用 setLights() 来实现效果。它又三个参数,第一个是设置灯的颜色,第二个是灯亮的时间,第三个则是灯暗的时间。如下:
.setLights(Color.RED,1000,1000)
同理,用默认的
.setDefaults(NotificationCompat.DEFAULT_LIGHTS)
ps:在国内百花齐放的环境中,上面那玩意基本无效,只能看各自的厂商的说明文档去适配了。
如果你觉得,上面的设置太麻烦,还有一个方法,直接全部设置成默认的:
.setDefaults(NotificationCompat.DEFAULT_ALL)
在实际应用中,我们常常需要配合一下实际场所来灵活应用通知栏。比如长文字,打图片、回复信息、或者跳转等。下面一起来学习。
优先级在 7.1 及以下有用,8.0 则使用 channel 来设置。
通知栏是可以设置优先级的,它有5个常亮可以选
比如,我们设置了 PRIORITY_MAX ,直接回显示出通知栏的效果:
很多时候,我们想显示一段比较长的文字,或者一个比较大的图片,使用默认的 setContentText 或者 setLargeIcon 是不行的,但是可以使用 setStyle ,setStyle 可以让通知栏变大来显示通知。
比如,显示一段长文字:
.setStyle(new NotificationCompat.BigTextStyle().bigText("我是内容,我是demo\n我不是测试\n 我是长文字啊"))
设置一张图片:
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.update_app_top_bg))
.setStyle(new NotificationCompat.BigPictureStyle()
.bigPicture(BitmapFactory.decodeResource(getResources(),
R.mipmap.update_app_top_bg)).bigLargeIcon(null)
)
一个通知最多可以提供三个操作按钮,然该用户可以快速响应,比如暂停,上一曲下一曲这些常用的按钮,这里,可以通过 addAction 去编写,并把 PendingIntent 关联进去,比如广播:
mBuilder = new NotificationCompat.Builder(this)
......
.addAction(R.mipmap.enter,"上一曲",pi)
.addAction(R.mipmap.enter,"开始",pi)
.addAction(R.mipmap.enter,"下一曲",pi);
google 在 Android 7.0 (API 24) 中引入允许用户直接回复的的组件,使用 RemoeInput 设置好key,并把它交给 action,即可实现。先看效果
首先,创建 RemoteInput.Builder() 的实例,并设置好 key 值,这个后面在 intent 会拿到。
然后,创建 PendingIntent,为了方便实验,添加一个广播
最后,创建 Action,把 remoteInput 和 pendingIntent 穿进去,代码如下:
private NotificationCompat.Action getRemoveAction(){
//添加一个回复组件,
RemoteInput remoteInput = new RemoteInput.Builder(REPLY_KEY)
.build();
//添加一个 pendingIntent 的广播
PendingIntent replyPi = PendingIntent.getBroadcast(this,2,
new Intent("com.zhengsr.test"),PendingIntent.FLAG_UPDATE_CURRENT);
//构建 action
NotificationCompat.Action action = new NotificationCompat.Action.Builder(R.mipmap.enter,
"回复",replyPi).addRemoteInput(remoteInput).build();
return action;
}
然后直接添加 action 即可:
mBuilder = new NotificationCompat.Builder(this)
....
.addAction(getRemoveAction())
;
如果想要拿到用户的输入内容,则可以调用 RemoteInput.getResultsFromIntent(intent) ,即可拿到 Bundle 并拿到数据,如:
class MyBroadcastReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = RemoteInput.getResultsFromIntent(intent);
if (bundle != null) {
String replay = bundle.getString(REPLY_KEY);
Log.d(TAG, "zsr onReceive: "+replay);
}
}
}
同样,也可以使用 NotificationCompat.MessagingStyle 去专门传递消息。具体参考官方资料。
通知栏还可以显示进度条,在 builder 中使用 setProgress。
setProgress(int max, int progress, boolean indeterminate)
参数都能看得明白。比如,当我们开始的进度条,可以设置为:
setProgress(100,0,false)
更新的话,直接改变 progress 即可,如果想要取消,则 setProgress(0,0,false)就可
在某些情况下,就算屏幕锁屏了,一些通知还是要显示的,比如电话,闹钟等。当然,通知栏也支持,根据设备的情况,会分两种情况
可以通过设置 setFullScreenIntent(PendingIntent intent ,boolean highPriority) 来设置,如:
mBuilder = new NotificationCompat.Builder(this)
.setContentTitle("紧急通知")
.setContentText("这是一条紧急通知")
.setWhen(System.currentTimeMillis())
..
.setFullScreenIntent(pi,true)
其中 pi 为你要跳转的 PendingIntent。除了默认的情况,还可以通过设置 setVisibility(int visibility) 来设置锁屏屏幕的范围,共有三种选择:
一般情况下,系统的通知,并不能满足我们的需求,且为了保证每个版本的样式统一。都会采用自定义布局的形式。
需要注意的是。在创建自定义布局的时候,我们需要提供两个 layout,一个收起的视图,它的高度上限为 64dp。一个是展开之后,它的上限为 256dp。
一般的自定义布局中,我们可以借助通用模板去构建一个基本布局,即保留时间戳,通知图标等装饰,而自定义由标题和文本内容的区域。
这个时候,可以使用 NotificationCompat.DecoratedCustomViewStyle 设置到 style 中,一般步骤如下:
如果为多媒体播放控件创建自定义通知。可以使用NotificationCompat.DecoratedMediaCustomViewStyle 类
例如:
RemoteViews cusRemoveView = new RemoteViews(getPackageName(),R.layout.cus_notify_small);
RemoteViews cusRemoveExpandView = new RemoteViews(getPackageName(),R.layout.cus_notify_large);
mBuilder = new NotificationCompat.Builder(this)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setStyle(new NotificationCompat.DecoratedCustomViewStyle())
.setCustomContentView(cusRemoveView)
.setCustomBigContentView(cusRemoveExpandView);
其中,当我们在自定义布局时,通知的背景颜色可能因为版本而异,如果要跟随系统,在设置 TextView 控件时,可以使用 TextAppearance_Compat_Notification 样式,比如标题的TextAppearance_Compat_Notification_Title。 这样就能保证在不同版本中,textview 始终是正常显示的。比如 R.layout_cus_notify_small:
注意,目前layout只支持 LinearLayout、FrameLayout、RelativeLayout三种基本布局
而,R.layout_cus_notify_large 中,给其中一个 TextView设置红色,不设置 style,看看效果:
避免在 RemoteViews 上设置背景颜色,可能会导致文办颜色无法读取的问题
如果你不想用系统的时间戳,通知图标等。可以去掉 setStyle(),只添加 setCustomContentView 和 setCustomBigContentView 即可。
要支持低于 Android 4.1(API 级别 16)的 Android 版本,您还应调用 setContent(),向其传递同一 RemoteViews 对象。
如需获取更多使用通知的示例代码,请参阅 Android 通知示例。