通知是安卓中比较常见的一种展示后台发生的消息的方式,使用 NotificationManager 发送一个 Notification 类型的消息,使用方法大多是先获取一个通知的系统服务类然后创建一个通知并添加通知布局样式和点击跳转方式等属性,最后 mNotificationManager.notify(NOTIFY_ID, mNotification); 发送一个通知。
实现一个大体的通知样式的过程是:
private NotificationManager mNotificationManager;
private Notification mNotification;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
public void showNotification(View view) {
int icon = R.mipmap.ic_launcher;
CharSequence tickerText = "开始下载";
long when = System.currentTimeMillis();
mNotification = new Notification(icon,tickerText,when);
mNotification.flags =Notification.FLAG_AUTO_CANCEL;
RemoteViews mRemoteView = new RemoteViews(getPackageName(),R.layout.remoteview_Layout);
mRemoteView.setTextViewText(R.id,title,"通知标题");
mNotification.contentView = mRemoteView;
Intent buttonIntent = new Intent(ACTION_CANCEL);
PendingIntent pendingIntent = PendingIntent.getActivities(this, 0,
SecondActivity.class, 0);
mNotification.contentIntent = pendingIntent;
mNotificationManager.notify(10,mNotification);
}
在很早的几个版本里我们可以这样写并且也能成功运行,但是现在里边好多属性已经过时了,甚至有的方法直接被取消了。
所以后来我们可以这样定义一个 Notification
Notification.Builder builder = new Notification.Builder(mContext);
builder.setContentTitle("这是通知标题");
builder.setContentText("这是通知内容");
//设置小图标
builder.setSmallIcon(R.mipmap.ic_launcher);
PendingIntent pendingIntent = PendingIntent.getActivities(this, 0,
SecondActivity.class, 0);
builder.setContentIntent(pendingIntent);
mNotification = builder.build();
mNotification.flags =Notification.FLAG_AUTO_CANCEL;
mNotificationManager.notify(10,mNotification);
使用 Notification.Builder 来 build 生成一个 Notification ,在 8.0 之前,这样写是没有问题的,但是在 8.0 之后,如果这样初始化一个 builder 运行后会报错的。错误是NotificationService: No Channel found for pkg=xxx.xxx.xxx, channelId=null, id=10, tag=null, opPkg=xxx.xxx.xxx, callingUid=10085, userId=0, incomingUserId=0, notificationUid=10085, notification=Notification…
错误的大致意思是没有一个设置的 Channel 匹配当前创建的通知,也就是没找到一个有 id 的 NotificationChannel 能发送当前的 notification,查看此处的源码,代码是这样写的
/**
* Constructs a new Builder with the defaults:
*
* @param context
* A {@link Context} that will be used by the Builder to construct the
* RemoteViews. The Context will not be held past the lifetime of this Builder
* object.
* @param channelId
* The constructed Notification will be posted on this
* {@link NotificationChannel}. To use a NotificationChannel, it must first be
* created using {@link NotificationManager#createNotificationChannel}.
*/
public Builder(Context context, String channelId) {
this(context, (Notification) null);
mN.mChannelId = channelId;
}
/**
* @deprecated use {@link Notification.Builder#Notification.Builder(Context, String)}
* instead. All posted Notifications must specify a NotificationChannel Id.
*/
@Deprecated
public Builder(Context context) {
this(context, (Notification) null);
}
@deprecated Notification.Builder#Notification.Builder(Context, String)}
instead. All posted Notifications must specify a NotificationChannel Id.
这的意思是Builder(Context context) 这种方法已经过时了,并且所有发送通知的方法都必须指定一个通知频道的 id 。
同时在 Builder(Context context, String channelId) 方法的注释处发现第二个参数的注释是这样写的, The constructed Notification will be posted on this {@link NotificationChannel}. To use a NotificationChannel, it must first be created using NotificationManager#createNotificationChannel.也就是要想使用 NotificationChannel 必须先用NotificationManager.createNotificationChannel 创建。所以改成下边这种写法:
@Override
public void onCreate() {
mManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
//ChannelId为"1",ChannelName为"Channel1"
NotificationChannel channel = new NotificationChannel("1",
"Channel1", NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(true); //是否在桌面icon右上角展示小红点
channel.setLightColor(Color.GREEN); //小红点颜色
channel.setShowBadge(true); //是否在久按桌面图标时显示此渠道的通知
mManager.createNotificationChannel(channel);
super.onCreate();
}
private void displayNotificationMessage(String message) {
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,
new Intent(this,MainActivity.class),0);
//这里的“1”对应上边创建的ChannelId为1
Notification.Builder builder = new Notification.Builder(this,"1");
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setContentTitle("服务通知标题");
builder.setContentText(message);
builder.setContentIntent(pendingIntent);
builder.setWhen(System.currentTimeMillis());
// RemoteViews contentView = new RemoteViews(getPackageName(),
// R.layout.download_notification_layout);
// contentView.setTextViewText(R.id.name, "正在下载...(点击取消下载)");
// builder.setCustomContentView(contentView);
Notification notification = builder.build();
notification.flags =Notification.FLAG_AUTO_CANCEL;
mManager.notify(10,notification);
}
然后在 8.0 及以上系统的手机上运行不会报错,说明必须这样设置一个 NotificationChannel 并且指明它的 id 。上边注释的 RemoteViews 是自定义通知布局用的,可以使用也可以通过上边 builder.setContentTitle("服务通知标题"); builder.setContentText(message); 这两个方法定义,可以根据业务任选一个。
最后在结束当前 activity 或者销毁通知前需要删除 NotificationChannel
NotificationChannel mChannel = mManager.getNotificationChannel("1");
mManager.deleteNotificationChannel(mChannel);