Notification是一个使用率很频繁的功能,但是你真的很清楚他到底有哪些功能吗?
本篇文章的代码已经上传的Github上,欢迎大家star,follow
那种基础概念什么的我就简单的说一下了,不过你要是问我通知栏的每一部分对应什么参数,我就不高兴回答了
基本属性
public Builder setTicker(CharSequence tickerText)
设置状态栏开始动画的文字
public Builder setContentTitle(CharSequence title)
设置内容区的标题,必须设置
public Builder setContentText(CharSequence text)
设置内容区的内容,必须设置
public Builder setContentIntent(PendingIntent intent)
设置点击通知后操作(可以跳转Activity,打开Service,或者发送广播)
public Builder setColor(@ColorInt int argb)
这个可以设置smallIcon的背景色
public Builder setSmallIcon(@DrawableRes int icon)
设置小图标,必须设置
*public Builder setLargeIcon(Bitmap b) *
设置打开通知栏后的大图标
*public Builder setWhen(long when) *
设置显示通知的时间,不设置默认获取系统时间,这个值会在Notification上面显示出来
*public Builder setAutoCancel(boolean autoCancel) *
设置为true,点击该条通知会自动删除,false时只能通过滑动来删除
public Builder setPriority(int pri)
设置优先级,级别高的排在前面
public Builder setDefaults(int defaults)
设置上述铃声,振动,闪烁用|分隔,常量在Notification里
public Builder setOngoing(boolean ongoing)
设置是否为一个正在进行中的通知,这一类型的通知将无法删除
通知的提醒方式
- 声音提醒
默认声音
notification.defaults |= Notification.DEFAULT_SOUND;
自定义声音
notification.sound = Uri.parse("file:///sdcard0/notification.ogg"); - 震动提醒
默认振动
notification.defaults |= Notification.DEFAULT_VIBRATE;
自定义振动
long[] vibrate = {100, 200, 300, 400}; //震动效果,表示在100、200、300、400这些时间点交替启动和关闭震动
notification.vibrate = vibrate; - 闪烁提醒
默认闪烁
notification.defaults |= Notification.DEFAULT_LIGHTS;
自定义闪烁
notification.ledARGB = 0xff00ff00; // LED灯的颜色,绿灯
notification.ledOnMS = 300; // LED灯显示的毫秒数,300毫秒
notification.ledOffMS = 1000; // LED灯关闭的毫秒数,1000毫秒
notification.flags |= Notification.FLAG_SHOW_LIGHTS; // 必须加上这个标志
PendingIntent
PendingIntent pendingIntent=PendingIntent.getActivity(MainActivity.this, (int) SystemClock.uptimeMillis(), new Intent(MainActivity.this, OpenActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
flags有四种不同的值:
FLAG_CANCEL_CURRENT:如果构建的PendingIntent已经存在,则取消前一个,重新构建一个。
FLAG_NO_CREATE:如果前一个PendingIntent已经不存在了,将不再构建它。
FLAG_ONE_SHOT:表明这里构建的PendingIntent只能使用一次。
FLAG_UPDATE_CURRENT:如果构建的PendingIntent已经存在,那么系统将不会重复创建,只是把之前不同的传值替换掉。通常做法就是在构建PendingIntent的时候传入不一样的requestCode来更新PendingIntent
最简单的通知
将之前提到的那些基础点串起来,就可以发送一条一行文本的通知了
NotificationManager manager= (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
public void sample(String ticker, String title, String content, int smallIcon, PendingIntent intent, boolean sound, boolean vibrate, boolean lights) {
builder.setTicker(ticker);
builder.setContentTitle(title);
builder.setContentText(content);
builder.setContentIntent(intent);
builder.setColor(Color.RED);
builder.setSmallIcon(smallIcon);
builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher));
builder.setWhen(System.currentTimeMillis());
builder.setAutoCancel(true);
builder.setPriority(NotificationCompat.PRIORITY_MAX);
int defaults=0;
if (sound) {
defaults |= Notification.DEFAULT_SOUND;
}
if (vibrate) {
defaults |= Notification.DEFAULT_VIBRATE;
}
if (lights) {
defaults |= Notification.DEFAULT_LIGHTS;
}
builder.setDefaults(defaults);
builder.setOngoing(true);
}
public void sendSingleLineNotification(String ticker, String title, String content, int smallIcon, PendingIntent intent, boolean sound, boolean vibrate, boolean lights) {
sample(ticker, title ,content, smallIcon, intent, sound, vibrate, lights);
Notification notification=builder.build();
send(notification);
}
大视图通知
从api16开始,通知出现了大视图的样式

大图通知一般分成3种,文字型(BigTextStyle)、图片型(BigPictureStyle)、列表型(InboxStyle)
处理这一类的通知,需要在基本配置上,外加一些处理
- 多行文本
public void sendMoreLineNotification(String ticker, String title, String content, int smallIcon, PendingIntent intent, boolean sound, boolean vibrate, boolean lights) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
Toast.makeText(context, "您的手机低于Android 4.1.2,不支持!!", Toast.LENGTH_SHORT).show();
return;
}
sample(ticker, title, content, smallIcon, intent, sound, vibrate, lights);
Notification notification=new NotificationCompat.BigTextStyle(builder).bigText(content).build();
send(notification);
}
多行文本比之前多一个bigText方法,放置好content即可
- 大图模式
public void sendBigPicNotification(String ticker, String title, String content, int smallIcon, PendingIntent intent, boolean sound, boolean vibrate, boolean lights) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
Toast.makeText(context, "您的手机低于Android 4.1.2,不支持!!", Toast.LENGTH_SHORT).show();
return;
}
sample(ticker, title, content, smallIcon, intent, sound, vibrate, lights);
//大图
Bitmap bigPicture=BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher);
//图标
Bitmap bigLargeIcon=BitmapFactory.decodeResource(context.getResources(), R.mipmap.android_bigicon);
Notification notification=new NotificationCompat.BigPictureStyle(builder).bigLargeIcon(bigLargeIcon).bigPicture(bigPicture).build();
send(notification);
}
bigPicture为那张大图,bigLargeIcon就是之前setLargeIcon位置上的Icon,这边之所以变成2个方法,是因为让两种展现形式效果不同,因为你可以通过滑动通知,来改变通知的样式
- 列表型
public void sendListNotification(String ticker, String title, String content, int smallIcon, PendingIntent intent, ArrayList<String> conntents, boolean sound, boolean vibrate, boolean lights) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
Toast.makeText(context, "您的手机低于Android 4.1.2,不支持!!", Toast.LENGTH_SHORT).show();
return;
}
sample(ticker, title, content, smallIcon, intent, sound, vibrate, lights);
NotificationCompat.InboxStyle style=new NotificationCompat.InboxStyle(builder);
for (String conntent : conntents) {
style.addLine(conntent);
}
style.setSummaryText(conntents.size()+"条消息");
style.setBigContentTitle(title);
Notification notification=style.build();
send(notification);
}
addLine就是中间列表部分,setSummaryText就是底部文字,setBigContentTitle就是标题

添加可点击的按钮的通知

public void sendActionNotification(String ticker, String title, String content, int smallIcon, PendingIntent intent, int leftIcon, String leftText, PendingIntent leftPI, int rightIcon, String rightText, PendingIntent rightPI, boolean sound, boolean vibrate, boolean lights) {
sample(ticker, title, content, smallIcon, intent, sound, vibrate, lights);
builder.addAction(leftIcon, leftText, leftPI);
builder.addAction(rightIcon, rightText, rightPI);
Notification notification=builder.build();
send(notification);
}
只要传入按钮的文字、图标以及PendingIntent即可
带进度条的通知


这种一般在下载过程中使用的比较多
public void sendProgressNotification(String ticker, String title, String content, int smallIcon, PendingIntent intent, boolean sound, boolean vibrate, boolean lights) {
sample(ticker, title, content, smallIcon, intent, sound, vibrate, lights);
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<=100;i+=10) {
builder.setProgress(100, i, false);
send(builder.build());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//下载完成
builder.setContentText("下载完成").setProgress(0, 0, false);
send(builder.build());
}
}).start();
}
只要加上setProgress即可,三个参数分别是最大值、当前值、是否显示具体进度。我这里是模拟一个下载过程
自定义通知
自定义通知首先明确一点是要用RemoteViews来设置布局
PendingIntent remotePending=PendingIntent.getActivity(MainActivity.this, 0, new Intent(MainActivity.this, ShareActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews contentView=new RemoteViews(getPackageName(), R.layout.remoteview);
contentView.setTextViewText(R.id.share_content, "这是自定义的view");
contentView.setOnClickPendingIntent(R.id.share_facebook, remotePending);
contentView.setOnClickPendingIntent(R.id.share_twitter, remotePending);
RemoteViews bigContentView=new RemoteViews(getPackageName(), R.layout.bigcontentview);
bigContentView.setTextViewText(R.id.share_content, "这是自定义的view");
bigContentView.setOnClickPendingIntent(R.id.share_facebook, remotePending);
bigContentView.setOnClickPendingIntent(R.id.share_twitter, remotePending);
//这边写了2个RemoteViews,同样是因为在api大于等于16的情况下,如果视图超过一定范围,可以转变成bigContentView
public void sendCustomerNotification(String ticker, String title, String content, int smallIcon, PendingIntent intent, RemoteViews contentView, RemoteViews bigContentView, boolean sound, boolean vibrate, boolean lights) {
sample(ticker, title, content, smallIcon, intent, sound, vibrate, lights);
Notification notification=builder.build();
notification.bigContentView=bigContentView;
notification.contentView=contentView;
send(notification);
}
OK,功能介绍完成,现在介绍一些不平常的东西
高级玩法
- RemoteViews适配


我们在使用remoteViews的时候,最怕就是遇到这种情况:因为通知栏的背景色在不同rom上的效果不同,文本颜色就不好确定,你写成白的,那么在白色背景上就有问题,写成黑的,在黑色背景上就有问题。怎么办?之前在网上找的通过style进行处理的方式不可行,我在这里结合hackware大神提供的方法来获取通知的背景色
public static boolean isDarkNotificationTheme(Context context) {
return !isSimilarColor(Color.BLACK, getNotificationColor(context));
}
/**
* 获取通知栏颜色
* @param context
* @return
*/
public static int getNotificationColor(Context context) {
NotificationCompat.Builder builder=new NotificationCompat.Builder(context);
Notification notification=builder.build();
int layoutId=notification.contentView.getLayoutId();
ViewGroup viewGroup= (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null, false);
if (viewGroup.findViewById(android.R.id.title)!=null) {
return ((TextView) viewGroup.findViewById(android.R.id.title)).getCurrentTextColor();
}
return findColor(viewGroup);
}
private static boolean isSimilarColor(int baseColor, int color) {
int simpleBaseColor=baseColor|0xff000000;
int simpleColor=color|0xff000000;
int baseRed=Color.red(simpleBaseColor)-Color.red(simpleColor);
int baseGreen=Color.green(simpleBaseColor)-Color.green(simpleColor);
int baseBlue=Color.blue(simpleBaseColor)-Color.blue(simpleColor);
double value=Math.sqrt(baseRed*baseRed+baseGreen*baseGreen+baseBlue*baseBlue);
if (value<180.0) {
return true;
}
return false;
}
这里有几个注意点
- TextView textView= (TextView) viewGroup.findViewById(android.R.id.title);可能在有的手机上获取textview为空,所以我想notification的文本区域,系统默认肯定有一个值的,那我就直接遍历找到这个值即可
private static int findColor(ViewGroup viewGroupSource) {
int color=Color.TRANSPARENT;
LinkedList<ViewGroup> viewGroups=new LinkedList<>();
viewGroups.add(viewGroupSource);
while (viewGroups.size()>0) {
ViewGroup viewGroup1=viewGroups.getFirst();
for (int i = 0; i < viewGroup1.getChildCount(); i++) {
if (viewGroup1.getChildAt(i) instanceof ViewGroup) {
viewGroups.add((ViewGroup) viewGroup1.getChildAt(i));
}
else if (viewGroup1.getChildAt(i) instanceof TextView) {
if (((TextView) viewGroup1.getChildAt(i)).getCurrentTextColor()!=-1) {
color=((TextView) viewGroup1.getChildAt(i)).getCurrentTextColor();
}
}
}
viewGroups.remove(viewGroup1);
}
return color;
}
这样你就可以通过
contentView.setInt(R.id.share_content, "setTextColor", NotificationUtils.isDarkNotificationTheme(MainActivity.this)==true?Color.WHITE:Color.BLACK);
实现颜色替换的功能,setInt、setString的功能是通过反射进行操作的
文章到此结束,感谢大家的阅读
网友评论
Fatal Exception: java.lang.RuntimeException: bad array lengths
at android.os.Parcel.readIntArray(Parcel.java:926)
at android.app.INotificationManager$Stub$Proxy.enqueueNotificationWithTag(INotificationManager.java:777)
at android.app.NotificationManager.notify(NotificationManager.java:272)
at android.app.NotificationManager.notify(NotificationManager.java:211)
at cc.netpas.android_firewall.service.BackgroundDaemon$3.run(BackgroundDaemon.java:297)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:158)
at android.os.HandlerThread.run(HandlerThread.java:61)