熊猫儿
发表于 2016-9-12 15:03
android 特殊用户通知用法汇总--Notification源码分析
标签: android
2016-04-12 14:40 6311人阅读 评论(0) 收藏 举报
http://static.blog.csdn.net/images/category_icon.jpg 分类:
Android(69) http://static.blog.csdn.net/images/arrow_triangle%20_down.jpg
版权声明:转载请标明出处http://blog.csdn.net/self_study,对技术感兴趣的同鞋加群544645972一起交流
目录(?)[+]
一直用的Android手机,用过这么多的app,平时也会遇到有趣的通知提醒,在这里先总结两种吧,notification和图标数字,有的以后看到再研究。还有,推广一下哈,刚刚建立一个Q群544645972,有兴趣的加一下,一起成长。Notification Notification应该算是最常见的app通知方式了,网上资料也很多,各种使用方法官方文档也已经写的非常详细了:http://developer.android.com/intl/zh-cn/guide/topics/ui/notifiers/notifications.html。这里就介绍一下几种特殊的用法:动态改变 将一个notification的setOngoing属性设置为true之后,notification就能够一直停留在系统的通知栏直到cancel或者应用退出。所以有的时候需要实时去根据情景动态改变notification,这里以一个定时器的功能为例,需要每隔1s去更新一下notification,具体效果:
http://img.blog.csdn.net/20160423214113414
熊猫儿
发表于 2016-9-12 15:05
本帖最后由 熊猫儿 于 2016-9-13 08:35 编辑
非常简单的功能,代码也很简单:private Timer timer;private TimerTask task;...if (timer != null) return;timer = new Timer("time");task = new TimerTask() { @Override public void run() { showDynamicNotification(); }};timer.scheduleAtFixedRate(task, 0, 1000);private void showDynamicNotification() { L.i("show dynamic notification"); mBuilder = new NotificationCompat.Builder(NotificationActivity.this); RemoteViews view = new RemoteViews(getPackageName(), R.layout.layout_notification); view.setTextViewText(R.id.tv_number, parseDate()); view.setImageViewResource(R.id.iv_icon, R.mipmap.ic_launcher); Intent intent = new Intent(NOTIFY_ACTION); PendingIntent pendingIntent = PendingIntent.getBroadcast(NotificationActivity.this, 1000, intent, PendingIntent.FLAG_UPDATE_CURRENT); mBuilder.setSmallIcon(R.mipmap.ic_launcher) .setContentIntent(pendingIntent) .setTicker("you got a new message") .setOngoing(true) .setContent(view); notification = mBuilder.build(); notificationManager.notify(NOTIFY_ID2, notification);}private String parseDate() { SimpleDateFormat format = new SimpleDateFormat("yyyy hh:mm:ss", Locale.getDefault()); return format.format(System.currentTimeMillis());}
[*]
[*]
需要注意的是Notification.Builder 是 Android 3.0 (API 11) 引入的,为了兼容低版本,我们一般使用 Support V4 包提供的 NotificationCompat.Builder 来构建 Notification。要想动态更新notification,需要利用 NotificationManager.notify() 的 id 参数,该 id 在应用内需要唯一(如果不唯一,在有些4.x的手机上会出现pendingIntent无法响应的问题,在红米手机上出现过类似情况),要想更新特定 id 的通知,只需要创建新的 notification,并触发与之前所用 id 相同的 notification,如果之前的通知仍然可见,则系统会根据新notification 对象的内容更新该通知,相反,如果之前的通知已被清除,系统则会创建一个新通知。
熊猫儿
发表于 2016-9-13 08:35
在这个例子中使用的是完全自定义的remoteViews,remoteViews和普通view的更新机制不一样,网上资料很多,感兴趣的可以去仔细了解。还有一个就是PendingIntent,这就不详细介绍了,这里简单列一下PendingIntent的4个flag的作用
[*]FLAG_CANCEL_CURRENT:如果构建的PendingIntent已经存在,则取消前一个,重新构建一个。
[*]FLAG_NO_CREATE:如果前一个PendingIntent已经不存在了,将不再构建它。
[*]FLAG_ONE_SHOT:表明这里构建的PendingIntent只能使用一次。
[*]FLAG_UPDATE_CURRENT:如果构建的PendingIntent已经存在,则替换它,常用。
big view Notification有两种视觉风格,一种是标准视图(Normal view)、一种是大视图(Big view)。标准视图在Android中各版本是通用的,但是对于大视图而言,仅支持Android4.1+的版本,比如邮件,音乐等软件就会使用到这种大视图样式的扩展通知栏,系统提供了setStyle()函数用来设置大视图模式,一般情况下有三种模式提供选择:
[*]NotificationCompat.BigPictureStyle, 在细节部分显示一个256dp高度的位图
[*]NotificationCompat.BigTextStyle,在细节部分显示一个大的文本块。
[*]NotificationCompat.InboxStyle,在细节部分显示一段行文本。
http://img.blog.csdn.net/20160423214525362
在21版本之后增加了一个Notification.MediaStyle,这个可以达到类似
http://img.blog.csdn.net/20160423214616230
熊猫儿
发表于 2016-9-13 08:36
[*]的效果,基本和一些主流媒体播放器的界面类似了,在这就不具体介绍了,提供一篇资料:controllingMedia
如果不使用上面的几种style,完全自定义布局也是可以的,例如实现:
http://img.blog.csdn.net/20160423214638261
相关源码:Android custom notification for music player Example。
在这我就以一个简单的实现为例,效果如下:
http://img.blog.csdn.net/20160423214746059
代码:
RemoteViews smallView = new RemoteViews(getPackageName(), R.layout.layout_notification)smallView.setTextViewText(R.id.tv_number, parseDate())smallView.setImageViewResource(R.id.iv_icon, R.mipmap.ic_launcher)mBuilder = new NotificationCompat.Builder(NotificationActivity.this)mBuilder.setSmallIcon(R.mipmap.ic_launcher) .setNumber((int) (Math.random() * 1000)) //No longer displayed in the status bar as of API 21. .setTicker() .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS)// .setDeleteIntent() .setAutoCancel(true) .setWhen(0) .setPriority(NotificationCompat.PRIORITY_LOW)intent = new Intent(NOTIFY_ACTION)pendingIntent = PendingIntent.getBroadcast(NotificationActivity.this, 1000, intent, PendingIntent.FLAG_UPDATE_CURRENT)mBuilder.setContentIntent(pendingIntent)
熊猫儿
发表于 2016-9-13 08:42
//在5.0版本之后,可以支持在锁屏界面显示notificationif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){ mBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)}notification = mBuilder.build()notification.contentView = smallView//如果系统版本 >= Android 4.1,设置大视图 RemoteViewsif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { RemoteViews view = new RemoteViews(getPackageName(), R.layout.layout_big_notification) view.setTextViewText(R.id.tv_name, ) view.setOnClickPendingIntent(R.id.btn_click_close, PendingIntent.getBroadcast(NotificationActivity.this, 1001, new Intent(CLICK_ACTION), PendingIntent.FLAG_UPDATE_CURRENT)) //textview marquee property is useless for bigContentView notification.bigContentView = view}notificationManager.notify(NOTIFY_ID3, notification)
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
[*]25
[*]26
[*]27
[*]28
[*]29
[*]30
[*]31
[*]32
[*]33
[*]34
[*]35
[*]36
[*]37
[*]38
[*]39
[*]40
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
[*]25
[*]26
[*]27
[*]28
[*]29
[*]30
[*]31
[*]32
[*]33
[*]34
[*]35
[*]36
[*]37
[*]38
[*]39
[*]40
xml布局:<linearlayout android:background="#ef222222" android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="horizontal" android:padding="10dp" xmlns:android="http://schemas.android.com/apk/res/android"> <framelayout android:layout_height="150dp" android:layout_width="match_parent"> <imageview android:background="@mipmap/ic_launcher" android:id="@+id/iv_icon" android:layout_gravity="center_vertical" android:layout_height="wrap_content" android:layout_width="wrap_content"> <linearlayout android:layout_height="match_parent" android:layout_weight="1" android:layout_width="match_parent" android:orientation="vertical"> <textview android:ellipsize="marquee" android:fadingedge="horizontal" android:focusable="true" android:focusableintouchmode="true" android:gravity="center_horizontal|center_vertical" android:id="@+id/tv_name" android:layout_gravity="center" android:layout_height="wrap_content" android:layout_width="fill_parent" android:marqueerepeatlimit="marquee_forever" android:scrollhorizontally="false" android:singleline="true" android:textcolor="#fff" android:textsize="15sp" android:textstyle="bold"> <requestfocus> </requestfocus></textview><button android:background="#ef222222" android:id="@+id/btn_click_close" android:layout_gravity="center_horizontal" android:layout_height="40dp" android:layout_margintop="10dp" android:layout_width="40dp" android:text="X" android:textsize="30sp" type="submit"></button></linearlayout> </framelayout></imageview></linearlayout>
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
这里有几点需要着重说明一下
[*]setTicker函数在21版本之后已经Deprecated了,没有效果。
[*]监听notification删除函数setDeleteIntent是在11版本后新增的,而且setAutoCancel为true后,该函数会失效。
[*]setPriority函数用来给notification设置优先级,上面给的google文档中有很详细的介绍。
[*]21版本之后,可以支持在锁屏界面显示notification,这个在google文档中也有介绍,这个体验对于我个人来说感触很深,对于短信等私密性通知可以隐藏,但是对于一般毫无隐私的应用通知,就可以设置其为public,省去用户解锁,下拉通知栏的操作。
[*]自定义大图模式也是将自定义的RemoteViews赋值给notification.bigContentView变量,而且这个功能也只是在api16(4.1)之后生效。
[*]大图模式高度的设置有些奇怪,在上面的xml文件中,LinearLayout设置高度是无效的,必须要套一层FrameLayout,设置FrameLayout的高度才行,貌似定义最外层的LinearLayout的layoutParams是无效的。
[*]在bigContentView中是无法实现textview的marquee效果,而且事实也很奇怪,单独使用contentView,传入的remoteViews中的textview的marquee属性是好用的,但是一旦设置了bigContentView,contentView中的textview属性也失效了,这点使用的时候要注意。
熊猫儿
发表于 2016-9-13 08:46
浮动通知 这种效果大家应该在微信中看的很多,其实实现也很简单:
http://img.blog.csdn.net/20160423215030291
代码:RemoteViews headsUpView = new RemoteViews(getPackageName(), R.layout.layout_heads_up_notification)intent = new Intent(NOTIFY_ACTION)pendingIntent = PendingIntent.getBroadcast(NotificationActivity.this, 1000, intent, PendingIntent.FLAG_UPDATE_CURRENT)mBuilder = new NotificationCompat.Builder(NotificationActivity.this)mBuilder.setSmallIcon(R.mipmap.ic_launcher) .setContentTitle() .setContentText() .setNumber((int) (Math.random() * 1000)) .setTicker() //must set pendingintent for this notification, or will be crash .setContentIntent(pendingIntent) .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS) .setAutoCancel(true) .setWhen(0)notification = mBuilder.build()if (Build.VERSION.SDK_INT >= 21) { notification.priority = Notification.PRIORITY_MAX notification.headsUpContentView = headsUpView}notificationManager.notify(NOTIFY_ID1, notification)
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
这个效果非常的方便,用户都不需要直接下拉出通知栏,直接就能够看见,省去了多余操作,google官方文档介绍:http://developer.android.com/intl/zh-cn/guide/topics/ui/notifiers/notifications.html#Heads-up。headsUpContentView属性也只是在21版本时出现,使用的时候需要注意。notification常见问题总结 1.通过notification打开activity的时候,就要涉及到保存用户导航的问题,这个时候就要使用到activity task的相关内容了,我以前写过一篇博客中有介绍到activity task的内容:android深入解析Activity的launchMode启动模式,Intent Flag,taskAffinity,感兴趣的可以去看看。那么要实现点击notification打开指定activity,就需要设置相关的pendingIntent,有两种特殊的情况需要说明一下:
[*]第一种是需要打开该activity的整个task栈,也就是说父activity也需要同时全部打开,而且按照次序排列在task栈中。 但是这里会有一个问题,它在打开整个activity栈之前会先清空原先的activity task栈,所以最后在task栈中只剩下相关的几个activity,举个例子我要打开A->B->C的activity栈,但是我原先的activity栈中有D和C这两个activity,系统会直接按顺序关闭D和C这两个activity,接着按顺序打开A->B->C,这种情况在使用的时候需要注意。
熊猫儿
发表于 2016-9-13 08:47
[*]第二种是直接打开一个activity在一个单独的task栈中 这种情况会生成两个task栈, 这两种情况在google官方文档中已经详细介绍了:http://developer.android.com/intl/zh-cn/guide/topics/ui/notifiers/notifications.html#NotificationResponse。
2.我在以前的博客中曾经介绍过一个notification图标变成白块的问题:android5.0状态栏图标变成白色,这个问题在国产的很多rom中自己解决了,例如小米,锤子等,但是例如HTC和三星等rom仍然是有这样的问题,要重视起来啊
3.列表内容在2.3的时候直接使用RemoteViews rvMain = new RemoteViews(context.getPackageName(), R.layout.notification_layout);//TODO rvMain...NotificationCompat.Builder builder = new NotificationCompat.Builder(context) .setContent(rvMain);// TOOD ...
[*]1
[*]2
[*]3
[*]4
[*]5
[*]1
[*]2
[*]3
[*]4
[*]5
是无效的,需要换一种方式:RemoteViews rvMain = new RemoteViews(context.getPackageName(), R.layout.notification_layout);//TODO rmMain...NotificationCompat.Builder builder = new NotificationCompat.Builder(context) .setContent(rvMain);// TOOD ...Notification notification = builder.build();if(Build.VERSION.SDK_INT <= 10){ notification.contentView = rvMain;}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
4.通知栏上的操作事件: setContentIntent():用户点击通知时触发
setFullScreenIntent()://TODO 这个在通知显示的时候会被调用
setDeleteIntent():用户清除通知时触发,可以是点击清除按钮,也可以是左右滑动删除(当然了,前提是高版本)
2.3及以下是无法处理自定义布局中的操作事件的,这样我们就不要去考虑增加自定义按钮了。notification源码解析 分析一下源码,以NotificationManager.notify为入口进行分析:INotificationManager service = getService()......service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id, stripped, idOut, UserHandle.myUserId())
[*]1
[*]2
[*]3
[*]4
http://static.blog.csdn.net/images/save_snippets.png
[*]1
[*]2
[*]3
[*]4
getService()函数:static public INotificationManager getService(){ if (sService != null) { return sService; } IBinder b = ServiceManager.getService(); sService = INotificationManager.Stub.asInterface(b); return sService;}
熊猫儿
发表于 2016-9-13 08:49
本帖最后由 熊猫儿 于 2016-9-13 08:51 编辑
该函数通过ServiceManager.getService(“notification”)获取了INotificationManager的Binder对象,用来进行跨进程通信,Binder不太明白的可以看看我以前写的一篇博客:android IPC通信(下)-AIDL。这里获取的Binder对象就是NotificationManagerService,这里涉及的两个类要介绍一下,StatusBarManagerService和NotificationManagerService,这两个service都会在frameworks/base/services/java/com/android/server/SystemServer.java文件里面进行启动的:class ServerThread extends Thread { public void run() {...... StatusBarManagerService statusBar = null; NotificationManagerService notification = null;...... statusBar = new StatusBarManagerService(context, wm); ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);...... notification = new NotificationManagerService(context, statusBar, lights); ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);...... }}
[*]
[*]
我在早期的博客中介绍过SystemServer,system_server子进程是zygote通过forkSystemServer函数创建的,感兴趣的可以去看看android启动过程详细讲解。上面的代码就调用到了NotificationManagerService的enqueueNotificationWithTag方法,enqueueNotificationWithTag方法会调用到enqueueNotificationInternal方法,这个方法就是核心了,我们抽取其中比较重要的代码分析一下:void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, final int callingPid, final String tag, final int id, final Notification notification, int[] idOut, int incomingUserId) { ... //------这里会做一个限制,除了系统级别的应用之外,其他应用的notification数量会做限制, //------用来放置DOS攻击导致的泄露 // Limit the number of notifications that any given package except the android // package or a registered listener can enqueue.Prevents DOS attacks and deals with leaks. ... //------post到工作handler中进行工作 mHandler.post(new Runnable() { @Override public void run() { synchronized (mNotificationList) { // === Scoring === //------审查参数priority // 0. Sanitize inputs notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, Notification.PRIORITY_MAX); ..... //------初始化score // 1. initial score: buckets of 10, around the app [-20..20] final int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; //------将前面传递进来的Notification封装成一个StatusBarNotification对象,然后 //------和score封装成一个NotificationRecord对象,接着会调用handleGroupedNotificationLocked //------方法,看能否跳过下一步操作,额外的会对downloadManager进行单独处理 // 2. extract ranking signals from the notification data .....
http://blog.csdn.net/self_study/article/details/51055769
熊猫儿
发表于 2016-9-14 10:32
//------主要是统计notification的各种行为,另外将该上面封装好的NotificationRecord对象 //------加入到mNotificationList中,然后排序,排序外后,如果notification设置了smallIcon, //------调用所有NotificationListeners的notifyPostedLocked方法,通知有新的notification, //------传入的参数为上面封装成的StatusBarNotification对象。 // 3. Apply local rules ..... mRankingHelper.sort(mNotificationList); if (notification.getSmallIcon() != null) { StatusBarNotification oldSbn = (old != null) ? old.sbn : null; mListeners.notifyPostedLocked(n, oldSbn); } else { ...... } //通知status bar显示该notification buzzBeepBlinkLocked(r); } } });}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
[*]25
[*]26
[*]27
[*]28
[*]29
[*]30
[*]31
[*]32
[*]33
[*]34
[*]35
[*]36
[*]37
[*]38
[*]39
[*]40
[*]41
[*]42
[*]43
[*]44
[*]45
[*]46
[*]47
[*]48
[*]49
[*]50
[*]51
[*]52
[*]53
[*]54
[*]55
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
[*]25
[*]26
[*]27
[*]28
[*]29
[*]30
[*]31
[*]32
[*]33
[*]34
[*]35
[*]36
[*]37
[*]38
[*]39
[*]40
[*]41
[*]42
[*]43
[*]44
[*]45
[*]46
[*]47
[*]48
[*]49
[*]50
[*]51
[*]52
[*]53
[*]54
[*]55
notifyPostedLocked方法中会继续post到工作handler中,在该工作handler中调用notifyPosted方法,notifyPosted方法很简单,也是通过Binder调用到了NotificationListenerService中,这个NotificationListenerService中类很实用,它可以继承,用来监听系统notification的各种动作:Android 4.4 KitKat NotificationManagerService使用详解与原理分析(一)__使用详解。通知完成,最后异步操作就是调用buzzBeepBlinkLocked()方法去显示该notification了,这个函数也很长,但是职责很明确,确认是否需要声音,震动和闪光,如果需要,那么就发出声音,震动和闪光:private void buzzBeepBlinkLocked(NotificationRecord record) { ..... // Should this notification make noise, vibe, or use the LED? ...... // If we're not supposed to beep, vibrate, etc. then don't. ..... if (disableEffects == null && (!(record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 )) && (record.getUserId() == UserHandle.USER_ALL || record.getUserId() == currentUser || mUserProfiles.isCurrentProfile(record.getUserId())) && canInterrupt && mSystemReady && mAudioManager != null) { if (DBG) Slog.v(TAG, "Interrupting!"); sendAccessibilityEvent(notification, record.sbn.getPackageName()); // sound // should we use the default notification sound? (indicated either by // DEFAULT_SOUND or because notification.sound is pointing at // Settings.System.NOTIFICATION_SOUND) ..... // vibrate // Does the notification want to specify its own vibration? .... // light .... if (buzz || beep || blink) { EventLogTags.writeNotificationAlert(record.getKey(), buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0); mHandler.post(mBuzzBeepBlinked); }}
熊猫儿
发表于 2016-9-14 10:33
最后将mBuzzBeepBlinked post到工作handler,最后会调用到mStatusBar.buzzBeepBlinked(),mStatusBar是StatusBarManagerInternal对象,这个对象是在StatusBarManagerService中初始化,所以最后调用到了StatusBarManagerService中StatusBarManagerInternal的buzzBeepBlinked()方法:public void buzzBeepBlinked() { if (mBar != null) { try { mBar.buzzBeepBlinked(); } catch (RemoteException ex) { } }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
mBar是一个IStatusBar对象,这个mBar在哪里赋值的呢?看这里:http://www.programering.com/a/MTOzITNwATg.html,英文看不懂没关系,有中文版:http://home.bdqn.cn/thread-42153-1-1.html。所以最终调用到了CommandQueue类中,接着sendEmptyMessage给了内部的H类(貌似很喜欢用H这个单词作为Handler的命名,比如acitivity的启动:android 不能在子线程中更新ui的讨论和分析),接着调用了mCallbacks.buzzBeepBlinked()方法,这个mCallbacks就是BaseStatusBar,最终会将notification绘制出来,到这里一个notification就算是完成了。
注:我分析代码的时候看的代码是最新版本的api 23代码,buzzBeepBlinked()这个函数在BaseStatusBar类中是不存在的,绘制代码是在UpdateNotification()函数中,但是BaseStatusBar分明是继承了CommandQueue.Callbacks接口,却没有实现它,所以这个buzzBeepBlinked()函数到最后就莫名其妙失踪了,求大神指点,非常疑惑。相关资料http://www.tutorialsface.com/2015/08/android-custom-notification-tutorial/
http://developer.android.com/intl/zh-cn/guide/topics/ui/notifiers/notifications.html#Heads-up
http://glgjing.github.io/blog/2015/11/18/android-kai-fa-zhi-notification-xiang-jie/
http://www.codeceo.com/article/android-notification-4-types.html
http://www.itnose.net/detail/6169442.html
http://www.cnblogs.com/over140/p/4249503.html
http://blog.csdn.net/loongggdroid/article/details/17616509/
http://www.2cto.com/kf/201408/327782.html
http://blog.csdn.net/xxbs2003/article/details/19167331
http://www.jianshu.com/p/4d76b2bc8784
http://home.bdqn.cn/thread-42153-1-1.html图标数字 http://img.blog.csdn.net/20160423215947673
虽然说这是iOS上的风格,但是在某些手机上还是支持的,比如三星和HTC(m8t,6.0)的有些手机都可以,小米手机是个特例,它是根据notification的数量来自动生成的。
一般情况下,HTC和三星可以使用下面的函数生成public static void setBadge(Context context, int count) { String launcherClassName = getLauncherClassName(context); if (launcherClassName == null) { return; } Intent intent = new Intent(); intent.putExtra(, count); intent.putExtra(, context.getPackageName()); intent.putExtra(, launcherClassName); context.sendBroadcast(intent);}public static String getLauncherClassName(Context context) { PackageManager pm = context.getPackageManager(); Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); List resolveInfos = pm.queryIntentActivities(intent, 0); for (ResolveInfo resolveInfo : resolveInfos) { String pkgName = resolveInfo.activityInfo.applicationInfo.packageName; if (pkgName.equalsIgnoreCase(context.getPackageName())) { String className = resolveInfo.activityInfo.name; return className; } } return null;}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
[*]25
[*]26
[*]27
[*]28
[*]29
http://static.blog.csdn.net/images/save_snippets.png
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
[*]25
[*]26
[*]27
[*]28
[*]29
由于android碎片化太严重,所以在不同手机上适配起来是非常麻烦,不过还好在github上国人写了一个库可以覆盖挺多机型:ShortcutBadger,也可以参考一下:http://stackoverflow.com/questions/17565307/how-to-display-count-of-notifications-in-app-launcher-icon。源码https://github.com/zhaozepeng/notification