8.0通知栏新增通知渠道
从Android 8.0(API级别26)开始,所有通知必须要分配一个渠道,对于每个渠道,可以单独设置视觉和听觉行为。然后用户可以在设置中修改这些设置,根据应用程序来决定哪些通知可以显示或者隐藏。
创建通知渠道之后,程序无法修改通知行为,创建之后只有用户可以修改,程序只能修改渠道名称跟渠道描述。
我们可以为一个应用程序创建多个通知渠道,不同的通知类型用不同的渠道。例如重要通知用一个渠道,可以为这个渠道重要性设置成最高,不怎么重要的通知用一个渠道,这个渠道重要性设置成最低。
创建一个通知
要创建一个通知,有以下几个步骤:
1. 构造NotificationChannel对象,构造方法有三个参数:渠道id、渠道名称、渠道重要性级别。
2. 调用NotificationChannel.setDescription方法可以设置渠道描述。这个描述在系统设置中可以看到。
3. 调用NotificationManager.createNotificationChannel方法创建通知渠道。
以下是注册通知渠道的代码,记得先判断版本号是不是大于或者等于8.0,因为只有8.0以上才有通知渠道API。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//创建通知渠道
CharSequence name = "渠道名称1";
String description = "渠道描述1";
String channelId="channelId1";//渠道id
int importance = NotificationManager.IMPORTANCE_DEFAULT;//重要性级别
NotificationChannel mChannel = new NotificationChannel(channelId, name, importance);
mChannel.setDescription(description);//渠道描述
mChannel.enableLights(true);//是否显示通知指示灯
mChannel.enableVibration(true);//是否振动
NotificationManager notificationManager = (NotificationManager) getSystemService(
NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(mChannel);//创建通知渠道
}
创建通知渠道不会执行任何操作,所以在启动应用程序时调用以上代码最好。
执行以上代码,就能在设置->应用和通知->选择当前app->应用通知,在应用通知界面就能看到创建的通知渠道,如图1-1所示,可以单独开关当前的通知类别,还可以点击当前渠道,进入渠道详细界面,如图1-2所示,在渠道详细界面可以设置渠道的提示音,震动,屏幕锁定时显示方式等。
图1-1 单个app通知所有渠道列表
图1-2 渠道详细界面
默认情况下,通知的震动还有声音提示都是由NotificationManagerCompat类中重要性级别决定的,例如常量IMPORTANCE_DEFAULT和IMPORTANCE_HIGH,后面我们会讲到这些常量的具体作用。
如果你想改变该渠道的默认通知,可以调用NotificationChannel对象的方法进行修改。以下介绍了几个常用的方法:
- enableLights() 是否显示通知指示灯
- setLightColor() 设置通知灯颜色
- setVibrationPattern() 设置振动模式
注意:一旦创建了渠道,调用以上方法就会无效,只有用户在设置中才能修改。
上面那段代码只告诉了我们创建渠道,下面这段代码让我们在之前创建的渠道上发送一个通知。
//第二个参数与channelId对应
Notification.Builder builder = new Notification.Builder(this,channelId);
//icon title text必须包含,不然影响桌面图标小红点的展示
builder.setSmallIcon(android.R.drawable.stat_notify_chat)
.setContentTitle("通知渠道1->标题")
.setContentText("通知渠道1->内容")
.setNumber(3); //久按桌面图标时允许的此条通知的数量
Intent intent=new Intent(this,NotificationActivity.class);
PendingIntent ClickPending = PendingIntent.getActivity(this, 0, intent, 0);
builder.setContentIntent(ClickPending);
notificationManager.notify(id,builder.build());
用Notification.Builder构造通知对象时,传入第二个参数就是渠道id,用这个渠道id就能跟我们之前创建的渠道进行关联。设置内容跟发送系统通知代码跟之前类似。运行以上代码就能在8.0的手机上显示通知了。
设置渠道重要性级别
渠道重要性级别影响该渠道中所有通知的显示,在创建NotificationChannel对象的构造方法中必须要指定级别,一共有5个重要性界别,范围从 IMPORTANCE_NONE(0)至 IMPORTANCE_HIGH(4),如表1所示。
用户可见的重要性级别 | 重要性(Android 8.0及更高版本) |
---|---|
紧急(发出声音并显示为提醒通知) | IMPORTANCE_HIGH |
高(发出声音) | IMPORTANCE_DEFAULT |
中等(没有声音) | IMPORTANCE_LOW |
低(无声音并且不会出现在状态栏中) | IMPORTANCE_MIN |
表1-1 渠道重要级别
查看渠道设置
我们都知道渠道创建之后不能通过代码修改,但是可以先查看该渠道的振动和声音等行为,如果需要修改,可以根据返回的内容再提示用户手动去打开。
1. 调用NotificationManager.getNotificationChannel(String channelId)方法获取NotificationChannel对象,这个方法有个参数渠道id。
2. 有了NotificationChannel对象就能调用getVibrationPattern、getSound、getImportance等方法。
示例代码如下所示:
NotificationChannel notificationChannel=notificationManager.getNotificationChannel(channelId);
long[] vibrationPattern=notificationChannel.getVibrationPattern();//震动模式
if(vibrationPattern!=null){
Log.i("ansen","震动模式:"+vibrationPattern.length);
}
Uri uri=notificationChannel.getSound();//通知声音
Log.i("ansen","通知声音:"+uri.toString());
int importance=notificationChannel.getImportance();//通知等级
Log.i("ansen","通知等级:"+importance);
打开通知渠道设置
创建渠道之后,代码无法去修改这个渠道的行为,只有用户去设置中进行修改,为了让用户更快的找到当前渠道,可以Intent使用ACTION_CHANNEL_NOTIFICATION_SETTINGS打开通知渠道的系统设置。
以下代码打开通知渠道的设置界面:
Intent channelIntent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
channelIntent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
channelIntent.putExtra(Settings.EXTRA_CHANNEL_ID,channelId);//渠道id必须是我们之前注册的
startActivity(channelIntent);
需要传入两个参数,应用程序的包名跟渠道id。
删除通知渠道
调用deleteNotificationChannel(String channelId)方法删除渠道,代码如下所示:
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.deleteNotificationChannel(channelId);
8.0通知栏点击通知发送广播
前面的案例我们点击通知栏都是跳转到指定Activity,但是PendingIntent除了getActivity方法之外,还有getBroadcast跟getService。可以点击通知发送广播,开启Service。
于是我们修改显示通知的代码:
String BROADCAST_ACTION="android.intent.action.BROADCAST_ACTION";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//第二个参数与channelId对应
Notification.Builder builder = new Notification.Builder(this,channelId);
//icon title text必须包含,不然影响桌面图标小红点的展示
builder.setSmallIcon(android.R.drawable.stat_notify_chat)
.setContentTitle("通知渠道1->标题")
.setContentText("通知渠道1->内容")
.setNumber(3); //长按桌面图标时允许的此条通知的数量
Intent intent = new Intent(BROADCAST_ACTION);
intent.putExtra("data","12345");//带上参数
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,id,intent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(pendingIntent);
builder.setAutoCancel(true);
mNotificationManager.notify(id,builder.build());
}
新建Intent对象的时候就传入了一个action,同时给Intent传入一个字符串参数,然后调用PendingIntent.getBroadcast构造PendingIntent对象,最后调用notify方法显示通知。
新建一个类DynamicBroadcast,继承BroadcastReceiver,用来接收通知栏点击时发送的广播。在onReceive方法中打印一下我们传入的参数。
public class DynamicBroadcast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent){
String data = intent.getStringExtra("data");
Log.i("data",data);
}
}
前面的内容我们讲了广播的两种注册方式,静态注册跟动态注册,这里我们使用静态注册,在AndroidManifest.xml文件中application标签中增加如下代码:
<receiver android:name=".DynamicBroadcast"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BROADCAST_ACTION" />
</intent-filter>
</receiver>
运行之后发现在Android8.0版本以下的手机正常,点击通知栏会打印广播的日志,但是在Android8.0版本或以上版本点击通知栏发现就没收到广播,我以为是8.0增加了通知渠道的问题,后面查看官网API,在Broadcasts类下面看到了这句话:
Beginning with Android 8.0 (API level 26), the
system imposes additional restrictions on
manifest-declared receivers. If your app targets
API level 26 or higher, you cannot use the manifest
to declare a receiver for most implicit broadcasts
(broadcasts that do not target your app
specifically).
大概意思是从Android8.0API级别26)开始,无法在AndroidManifest.xml文件中声明隐式广播,系统的隐式广播正常使用。
所以呢如果你的手机是Android8.0以上版本的,就需要动态注册广播,这样才能接收到通知栏点击时发送的广播。
注释掉AndroidManifest.xml文件中声明的广播,然后在MainActivity的onCreate方法中注册广播,代码如下:
//动态注册广播
dynamicBroadcast=new DynamicBroadcast();
IntentFilter intentFilter=new IntentFilter(BROADCAST_ACTION);
registerReceiver(dynamicBroadcast,intentFilter);
静态注册的广播一定要在onDestroy方法中进行反注册:
@Override
protected void onDestroy() {
super.onDestroy();
if(dynamicBroadcast!=null){
unregisterReceiver(dynamicBroadcast);//取消注册广播
}
}
上一篇: 判断输入的字符串是否是回文
下一篇: python数据分析与挖掘(一)