您的位置:首页 > 运维架构

Smack PacketReader 监听器启动过程分析

2014-11-24 21:24 225 查看
Smack PacketReader 监听器启动过程分析

一、数据进入线程池

newSingleThreadExecutor

创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

PacketReader中的 listenerExecutor就是一个 newSingleThreadExecutor。

listenerExecutor.submit(new ListenerNotification(packet));  //在这里packet 进入线程池,并由ListenerNotification开启监听模式。

通过submit方法,PacketReader 将从xml解析成java对象的packet 封装在 ListenerNotification 中 提交到线程池去执行。

二、线程的执行

ListenerNotification 实现了Runnable接口,进入线程池后做为一个线程被执行。

执行的时候,从connect 成员变量 recvListeners 中读取 ListenerWrapper,并将packet数据交给 notifyListener 执行 。

只要知道 recvListeners 的数据从何而来,就知道 recvListeners 里面有什么数据了。

    private class ListenerNotification implements Runnable {

        private Packet packet;

        public ListenerNotification(Packet packet) {

            this.packet = packet;

        }

        public void run() {

            for (ListenerWrapper listenerWrapper : connection.recvListeners.values()) {

                listenerWrapper.notifyListener(packet);

            }

        }

    }

三、recvListeners的数据来源

recvListeners 数据添加只有这一处:来自 XmppConnection 的父类 Connect 的 addPacketListener :

在调用 addPacketListener 的时候,实际上参数 packetListener 和  packetFilter 被 ListenerWrapper 封装后存入了 recvListeners中。

    public void addPacketListener(PacketListener packetListener, PacketFilter packetFilter) {

        if (packetListener == null) {

            throw new NullPointerException("Packet listener is null.");

        }

        ListenerWrapper wrapper = new ListenerWrapper(packetListener, packetFilter);

        recvListeners.put(packetListener, wrapper);

    }

四、recvListeners的数据什么时候加入

connect.addPacketListener() 方法应该在 connect.setPacket()调用之前调用。

也就是当程序需要通过connect发送数据的时候(比如执行 connect.connect()  connect.setPacket()),需要在发送之前设置connect的 packetListener 和 packetFilter 。

下面是 androidpn客户端 用户注册的部分代码:

[java] view
plaincopy





PacketFilter packetFilter = new AndFilter(new PacketIDFilter(registration.getPacketID()), new PacketTypeFilter(IQ.class));  

  

PacketListener packetListener = new PacketListener() {  

             

         public void processPacket(Packet packet) {  

              if (packet instanceof IQ) {  

                  IQ response = (IQ) packet;  

                  if (response.getType() == IQ.Type.ERROR) {  

                       if (!response.getError().toString().contains("409")) {  

                            Log.e(LOGTAG, "Unknown error while registering XMPP account! " + response.getError().getCondition());  

                       }  

                  } else if (response.getType() == IQ.Type.RESULT) {  

                       xmppManager.setUsername(newUsername);  

                       xmppManager.setPassword(newPassword);  

                       Editor editor = sharedPrefs.edit();  

                       editor.putString(Constants.XMPP_USERNAME, newUsername);  

                       editor.putString(Constants.XMPP_PASSWORD, newPassword);  

                       editor.commit();  

                       Log.i(LOGTAG, "Account registered successfully");  

                       xmppManager.runTask();  

                 }  

            }  

        }  

};  

  

connection.addPacketListener(packetListener, packetFilter);  

    

五、监听机制

只要在调用connect.setPacke等通讯方法的时候,就要先调用 connect.addPacketListener ,将 PacketListener 和 PacketFilter封装在ListenerWrapper中,保存在队列中。

listenerWrapper通过调用 nofityListener() 方法,启动监听事件。

[java] view
plaincopy





    

    

protected static class ListenerWrapper {  

  

        private PacketListener packetListener;  

        private PacketFilter packetFilter;  

  

        /** 

         * Create a class which associates a packet filter with a listener. 

         *  

         * @param packetListener the packet listener. 

         * @param packetFilter the associated filter or null if it listen for all packets. 

         */  

        public ListenerWrapper(PacketListener packetListener, PacketFilter packetFilter) {  

            this.packetListener = packetListener;  

            this.packetFilter = packetFilter;  

        }  

  

        /**  

[java] view
plaincopy





 * Notify and process the packet listener if the filter matches the packet.  

 *   

 * @param packet the packet which was sent or received.  

 */  

public void notifyListener(Packet packet) {  

    if (packetFilter == null || packetFilter.accept(packet)) {  

        packetListener.processPacket(packet);  

    }  

}  

notifyListener()方法调用自己封装的 filter和listener 的方法。

首先检查 packetFilter 并调用 packetFilter.accept()

然后执行packetListener.processPacket()

这两个类和方法都是在第四步设置的,在这里可以定义自己的逻辑处理数据。

总结:

本篇中,通过 packetFilter设置的 PacketTypeFilter 会影响对不同数据的处理。

转:http://blog.csdn.net/teamlet/article/details/25431155
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  XMPP IM Openfire Smack