Android 8.0及以上版本,通知消息不显示,不出现原因、问题解决、分析

 android  Android 8.0及以上版本,通知消息不显示,不出现原因、问题解决、分析已关闭评论
7月 022020
 

在学习《android权威编程指南》第3版28章通知消息时,发现使用书上的代码始终无法在测试机上显示状态栏通知,很是郁闷,后来终于在android官网的文档中找到了答案。(见: https://developer.android.com/training/notify-user/build-notification?hl=zh-cn#java

问题其实出在我的测试机的Android版本上 (我的机器是Android 9.0)。

官网对创建通知时, 有以下主要注意点:

  1. Android 8.0以上 NotificationCompat.Builder 构造函数除了要求context参数,还要求您提供channel  id参数。这是兼容 Android 8.0(API 级别 26)及更高版本所必需的,但会被较旧版本忽略。
  2. 也就是说Android 8.0及以上的版本, 必须先通过 createNotificationChannel() 创建NotificationChannel 的实例,  再将 NotificationChannel 的实例的id用于NotificationCompat.Builder的构造,在系统中注册应用的通知渠道,然后才能在 Android 8.0 及更高版本上提供通知。

 

就是说需要把书上的代码做以下改变:

原来的代码:

            Notification notification = new NotificationCompat.Builder(this)
                    .setTicker(resources.getString(R.string.new_pictures_title))
                    .setSmallIcon(android.R.drawable.ic_menu_report_image)
                    .setContentTitle(resources.getString(R.string.new_pictures_title))
                    .setContentText(resources.getString(R.string.new_pictures_text))
                    .setContentIntent(pi)
                    .setAutoCancel(true)
                    .build();

修改为新代码:

            NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
            String channelId = "default";
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
                String channelName = "默认通知";
                notificationManager.createNotificationChannel(new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH));
            }

            Notification notification = new NotificationCompat.Builder(this, channelId)
                    .setTicker(resources.getString(R.string.new_pictures_title))
                    .setSmallIcon(android.R.drawable.ic_menu_report_image)
                    .setContentTitle(resources.getString(R.string.new_pictures_title))
                    .setContentText(resources.getString(R.string.new_pictures_text))
                    .setContentIntent(pi)
                    .setAutoCancel(true)
                    .build();

DONE!!!

1月 062015
 

JMX学习(二)——通知 ,分享:

Notification   通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知.

 

 

这里写一个简单的Server配置例子, 首先定义我们的MBean接口:

 

 

Java代码 复制代码

  1. package com.haitao.jmx.mbeans.server;   
  2.   
  3. /**  
  4.  *   
  5.  * Server Configure MBean  
  6.  *   
  7.  * @author haitao.tu  
  8.  *  
  9.  */  
  10. public interface ServerConfigureMBean {   
  11.   
  12.     public void setPort(int port);   
  13.        
  14.     public int getPort();   
  15.        
  16.     public void setHost(String host);   
  17.        
  18.     public String getHost();   
  19.        
  20. }  
[java] view plaincopy

  1. package com.haitao.jmx.mbeans.server;  
  2.   
  3. /** 
  4.  *  
  5.  * Server Configure MBean 
  6.  *  
  7.  * @author haitao.tu 
  8.  * 
  9.  */  
  10. public interface ServerConfigureMBean {  
  11.   
  12.     public void setPort(int port);  
  13.       
  14.     public int getPort();  
  15.       
  16.     public void setHost(String host);  
  17.       
  18.     public String getHost();  
  19.       
  20. }  

 

 

 

接着,我们会想第一节那样,去实现这个MBean接口,并且继承NotificationBroadcasterSupport,来提供广播服务:

 

 

Java代码 复制代码

  1. package com.haitao.jmx.mbeans.server;   
  2.   
  3. import java.util.concurrent.atomic.AtomicLong;   
  4.   
  5. import javax.management.AttributeChangeNotification;   
  6. import javax.management.NotificationBroadcasterSupport;   
  7.   
  8. /**  
  9.  * Server Configure  
  10.  *   
  11.  * @author haitao.tu  
  12.  *  
  13.  */  
  14. public class ServerConfigure extends NotificationBroadcasterSupport implements ServerConfigureMBean {   
  15.        
  16.     private AtomicLong sequenceNumber = new AtomicLong(1);   
  17.   
  18.     private int port;   
  19.   
  20.     private String host;   
  21.   
  22.     @Override  
  23.     public void setPort(int port) {   
  24.         int oldPort = this.port;   
  25.         this.port = port;   
  26.         AttributeChangeNotification notification = new AttributeChangeNotification(   
  27.                 this,   
  28.                 sequenceNumber.getAndIncrement(),   
  29.                 System.currentTimeMillis(),   
  30.                 AttributeChangeNotification.ATTRIBUTE_CHANGE,   
  31.                 “Server Port Change”,   
  32.                 “java.lang.Integer”,   
  33.                 oldPort + “”,   
  34.                 this.port + “”  
  35.                 );   
  36.         super.sendNotification(notification);   
  37.     }   
  38.   
  39.     @Override  
  40.     public void setHost(String host) {   
  41.         String oldHost = this.host;   
  42.         this.host = host;   
  43.         AttributeChangeNotification notification = new AttributeChangeNotification(   
  44.                 this,   
  45.                 sequenceNumber.getAndIncrement(),   
  46.                 System.currentTimeMillis(),   
  47.                 AttributeChangeNotification.ATTRIBUTE_CHANGE,   
  48.                 “Server Host Change”,   
  49.                 “java.lang.String”,   
  50.                 oldHost,   
  51.                 this.host   
  52.                 );   
  53.         super.sendNotification(notification);   
  54.     }   
  55.   
  56.     @Override  
  57.     public int getPort() {   
  58.         return port;   
  59.     }   
  60.   
  61.     @Override  
  62.     public String getHost() {   
  63.         return host;   
  64.     }   
  65.   
  66. }  
[java] view plaincopy

  1. package com.haitao.jmx.mbeans.server;  
  2.   
  3. import java.util.concurrent.atomic.AtomicLong;  
  4.   
  5. import javax.management.AttributeChangeNotification;  
  6. import javax.management.NotificationBroadcasterSupport;  
  7.   
  8. /** 
  9.  * Server Configure 
  10.  *  
  11.  * @author haitao.tu 
  12.  * 
  13.  */  
  14. public class ServerConfigure extends NotificationBroadcasterSupport implements ServerConfigureMBean {  
  15.       
  16.     private AtomicLong sequenceNumber = new AtomicLong(1);  
  17.   
  18.     private int port;  
  19.   
  20.     private String host;  
  21.   
  22.     @Override  
  23.     public void setPort(int port) {  
  24.         int oldPort = this.port;  
  25.         this.port = port;  
  26.         AttributeChangeNotification notification = new AttributeChangeNotification(  
  27.                 this,  
  28.                 sequenceNumber.getAndIncrement(),  
  29.                 System.currentTimeMillis(),  
  30.                 AttributeChangeNotification.ATTRIBUTE_CHANGE,  
  31.                 “Server Port Change”,  
  32.                 “java.lang.Integer”,  
  33.                 oldPort + “”,  
  34.                 this.port + “”  
  35.                 );  
  36.         super.sendNotification(notification);  
  37.     }  
  38.   
  39.     @Override  
  40.     public void setHost(String host) {  
  41.         String oldHost = this.host;  
  42.         this.host = host;  
  43.         AttributeChangeNotification notification = new AttributeChangeNotification(  
  44.                 this,  
  45.                 sequenceNumber.getAndIncrement(),  
  46.                 System.currentTimeMillis(),  
  47.                 AttributeChangeNotification.ATTRIBUTE_CHANGE,  
  48.                 “Server Host Change”,  
  49.                 “java.lang.String”,  
  50.                 oldHost,  
  51.                 this.host  
  52.                 );  
  53.         super.sendNotification(notification);  
  54.     }  
  55.   
  56.     @Override  
  57.     public int getPort() {  
  58.         return port;  
  59.     }  
  60.   
  61.     @Override  
  62.     public String getHost() {  
  63.         return host;  
  64.     }  
  65.   
  66. }  

 

 

在setPort与setHos方法中,首先new了一个AttributeChangeNotification,这个类是javax.management.Notification的子类,而javax.management.Notification

这个类又是java.util.EventObject的子类,由此可以证实上边所说的,JMX通知机制使用了观察者设计模式.

 

javax.management.Notification是一个JMX的通知核心类,将来需要扩展或者其他JMX自带的消息,均集成自此类.

 

AttributeChangeNotification根据类名可知,是一个属性改变的通知,造方法参数如下:

 

 

Object source,                 // 事件源,一直传递到java.util.EventObject的source

long sequenceNumber,   // 通知序号,标识每次通知的计数器

long timeStamp,              // 通知发出的时间戳 

String msg,                     // 通知发送的message

String attributeName,     // 被修改属性名

String attributeType,      // 被修改属性类型

Object oldValue,             // 被修改属性修改以前的值

Object newValue            // 被修改属性修改以后的值

 

 

根据观察者模式,由事件与广播组成,所以这里继承了NotificationBroadcasterSupport,来提供广播机制,

 

调用NotificationBroadcasterSupportr的sendNotification(notification) 发送广播,广播会根据注册的观察者

 

来对观察者进行逐一通知.

 

 

sendNotification 在JDK1.6是通过Executor来发送通知,默认调用线程同步发送:

 

 

Java代码 复制代码

  1. public NotificationBroadcasterSupport(Executor executor,   
  2.                       MBeanNotificationInfo… info) {   
  3.     this.executor = (executor != null) ? executor : defaultExecutor;   
  4.   
  5.     notifInfo = info == null ? NO_NOTIFICATION_INFO : info.clone();   
  6.     }  
[java] view plaincopy

  1. public NotificationBroadcasterSupport(Executor executor,  
  2.                       MBeanNotificationInfo… info) {  
  3.     this.executor = (executor != null) ? executor : defaultExecutor;  
  4.   
  5.     notifInfo = info == null ? NO_NOTIFICATION_INFO : info.clone();  
  6.     }  

 

 

 

Java代码 复制代码

  1. private final static Executor defaultExecutor = new Executor() {   
  2.         // DirectExecutor using caller thread   
  3.         public void execute(Runnable r) {   
  4.         r.run();   
  5.         }   
  6.     };   
[java] view plaincopy

  1. private final static Executor defaultExecutor = new Executor() {  
  2.         // DirectExecutor using caller thread  
  3.         public void execute(Runnable r) {  
  4.         r.run();  
  5.         }  
  6.     };   

 

 

如果想用异步发送通知,大家可以在构造方法中传入异步执行的Executor , 例如 ThreadPoolExecutor.

 

接下来,还得写一个观察者,来接受我们送出的通知:

 

 

Java代码 复制代码

  1. package com.haitao.jmx.mbeans.server;   
  2.   
  3. import javax.management.Notification;   
  4. import javax.management.NotificationListener;   
  5.   
  6. /**  
  7.  * Server Configure Notification Listener  
  8.  *   
  9.  * @author haitao.tu  
  10.  *   
  11.  */  
  12. public class ServerConfigureNotificationListener implements  
  13.         NotificationListener {   
  14.   
  15.     @Override  
  16.     public void handleNotification(Notification notification, Object handback) {   
  17.         log(“SequenceNumber:” + notification.getSequenceNumber());   
  18.         log(“Type:” + notification.getType());   
  19.         log(“Message:” + notification.getMessage());   
  20.         log(“Source:” + notification.getSource());   
  21.         log(“TimeStamp:” + notification.getTimeStamp());   
  22.     }   
  23.   
  24.     private void log(String message) {   
  25.         System.out.println(message);   
  26.     }   
  27.   
  28. }  
[java] view plaincopy

  1. package com.haitao.jmx.mbeans.server;  
  2.   
  3. import javax.management.Notification;  
  4. import javax.management.NotificationListener;  
  5.   
  6. /** 
  7.  * Server Configure Notification Listener 
  8.  *  
  9.  * @author haitao.tu 
  10.  *  
  11.  */  
  12. public class ServerConfigureNotificationListener implements  
  13.         NotificationListener {  
  14.   
  15.     @Override  
  16.     public void handleNotification(Notification notification, Object handback) {  
  17.         log(“SequenceNumber:” + notification.getSequenceNumber());  
  18.         log(“Type:” + notification.getType());  
  19.         log(“Message:” + notification.getMessage());  
  20.         log(“Source:” + notification.getSource());  
  21.         log(“TimeStamp:” + notification.getTimeStamp());  
  22.     }  
  23.   
  24.     private void log(String message) {  
  25.         System.out.println(message);  
  26.     }  
  27.   
  28. }  

 

这里只是简单输出了通知内容, 在这个类中我们实现NotificationListener接口,可以看出该接口中只有一个方法,

就是处理消息,顺藤摸瓜,在看一下NotificationListener的接口代码:

 

 

Java代码 复制代码

  1. package javax.management;   
  2.   
  3.   
  4. import java.util.EventListener;   
  5.   
  6.   
  7. /**  
  8.  * Should be implemented by an object that wants to receive notifications.  
  9.  *  
  10.  * @since 1.5  
  11.  */  
  12. public interface NotificationListener extends java.util.EventListener   {    
  13.   
  14.     /**  
  15.     * Invoked when a JMX notification occurs.  
  16.     * The implementation of this method should return as soon as possible, to avoid  
  17.     * blocking its notification broadcaster.  
  18.     *  
  19.     * @param notification The notification.      
  20.     * @param handback An opaque object which helps the listener to associate information 
  21.     * regarding the MBean emitter. This object is passed to the MBean during the  
  22.     * addListener call and resent, without modification, to the listener. The MBean object  
  23.     * should not use or modify the object.   
  24.     *  
  25.     */  
  26.     public void handleNotification(Notification notification, Object handback) ;   
  27. }  
[java] view plaincopy

  1. package javax.management;  
  2.   
  3.   
  4. import java.util.EventListener;  
  5.   
  6.   
  7. /** 
  8.  * Should be implemented by an object that wants to receive notifications. 
  9.  * 
  10.  * @since 1.5 
  11.  */  
  12. public interface NotificationListener extends java.util.EventListener   {   
  13.   
  14.     /** 
  15.     * Invoked when a JMX notification occurs. 
  16.     * The implementation of this method should return as soon as possible, to avoid 
  17.     * blocking its notification broadcaster. 
  18.     * 
  19.     * @param notification The notification.     
  20.     * @param handback An opaque object which helps the listener to associate information 
  21.     * regarding the MBean emitter. This object is passed to the MBean during the 
  22.     * addListener call and resent, without modification, to the listener. The MBean object  
  23.     * should not use or modify the object.  
  24.     * 
  25.     */  
  26.     public void handleNotification(Notification notification, Object handback) ;  
  27. }  

 

可以很清楚的看出继承了java.util.EventListener接口,又一次证实了,JMX通知机制是观察者模式的衍生产品.

 

好了,所有的功能代码都写完了,下边需要测试一JMX的通知机制:

 

这里还需要写一个测试用例来支持:

 

 

Java代码 复制代码

  1. package com.haitao.jmx.mbeans.server;   
  2.   
  3. import java.lang.management.ManagementFactory;   
  4.   
  5. import javax.management.MBeanServer;   
  6. import javax.management.ObjectName;   
  7.   
  8. public class ServerStartup {   
  9.   
  10.     public static void main(String[] args) throws Exception {   
  11.         // 创建MBeanServer   
  12.         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();   
  13.         // 新建MBean ObjectName, 在MBeanServer里标识注册的MBean   
  14.         ObjectName name = new ObjectName(“com.haitao.jmx.mbeans.server:type=ServerConfigure”);   
  15.         // 创建MBean   
  16.         ServerConfigure mbean = new ServerConfigure();   
  17.         // 在MBeanServer里注册MBean, 标识为ObjectName(com.haitao.jmx.mbeans.server:type=ServerConfigure)   
  18.         mbs.registerMBean(mbean, name);   
  19.         // 自定义观察者   
  20.         ServerConfigureNotificationListener listener = new ServerConfigureNotificationListener();   
  21.         // 加入MBeanServer   
  22.         mbs.addNotificationListener(name, listener, nullnull);   
  23.         Thread.sleep(Long.MAX_VALUE);   
  24.     }   
  25.        
  26. }  
[java] view plaincopy

  1. package com.haitao.jmx.mbeans.server;  
  2.   
  3. import java.lang.management.ManagementFactory;  
  4.   
  5. import javax.management.MBeanServer;  
  6. import javax.management.ObjectName;  
  7.   
  8. public class ServerStartup {  
  9.   
  10.     public static void main(String[] args) throws Exception {  
  11.         // 创建MBeanServer  
  12.         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();  
  13.         // 新建MBean ObjectName, 在MBeanServer里标识注册的MBean  
  14.         ObjectName name = new ObjectName(“com.haitao.jmx.mbeans.server:type=ServerConfigure”);  
  15.         // 创建MBean  
  16.         ServerConfigure mbean = new ServerConfigure();  
  17.         // 在MBeanServer里注册MBean, 标识为ObjectName(com.haitao.jmx.mbeans.server:type=ServerConfigure)  
  18.         mbs.registerMBean(mbean, name);  
  19.         // 自定义观察者  
  20.         ServerConfigureNotificationListener listener = new ServerConfigureNotificationListener();  
  21.         // 加入MBeanServer  
  22.         mbs.addNotificationListener(name, listener, nullnull);  
  23.         Thread.sleep(Long.MAX_VALUE);  
  24.     }  
  25.       
  26. }  

 

最后,我们开始验证成果:

 

1.打开%JAVA_HOME%/bin/jconsole连接到本地进程:

 

 

jconsole

 

2. 进入MBean选项框, 点击左边的树,打开通知:

 

 

 

3. 订阅通知

 

 

 

4. 修改属性,产生通知

 

 

 

 

5. 验证通知

 

 

 

OK, 学习笔记二写完了,回想下一, 

 

1. JMX中要定义接口必须以xxxMBean的规范定义

2. 得有类实现xxxMBean接口

3. 在实现类中可以继承NotificationBroadcasterSupport来支持通知机制

4. 可以通过jconsole来验证

 转自:http://blog.csdn.net/qiao000_000/article/details/6061813