PacketReader 如何实现smack数据监听机制和packet分发机制


前面说过, PacketReader 在构造函数中传递 XmppConnection的实例,并赋给自己的成员变量 connect;

又启动了一个  readerThread 线程,在 parsePackets() 方法中处理connect的输入数据流 (也就是socket的数据输入流)。


这时读入的数据是xml格式的(格式说明参见 Xmpp协议),

 parsePackets()方法负责将xml数据转换为java对象,

转换为java对象后,parsePackets() 调用  processPacket()方法处理传入的Java对象。


processPacket()方法将传入的Java对象传递个另一个线程由另一线程来处理。


线程切换的语句:


listenerExecutor.submit(new ListenerNotification(packet));



listenerExecutor是单线程执行线程池

ExecutorService listenerExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {


public Thread newThread(Runnable runnable) {

Thread thread = new Thread(runnable, "Smack Listener Processor (" + connection.connectionCounterValue +")");

thread.setDaemon(true);

return thread;

}

});


执行的是线程是:

new ListenerNotification(packet);


所以,只要有数据从服务器端发送过来,经过转换后的java对象以packet的形式提交到线程池中,由 ListenerNotification 处理。

这有点类似触发器。


执行的是什么呢?


[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public void run() {  
  2.     for (ListenerWrapper listenerWrapper : connection.recvListeners.values()) {  
  3.         try {  
  4.             listenerWrapper.notifyListener(packet);  
  5.         } catch (Exception e) {  
  6.             System.err.println("Exception in packet listener: " + e);  
  7.             e.printStackTrace();  
  8.         }  
  9.     }  
  10. }  

只要有数据从服务器端传过来,转换后的packet对象要全部传递给 connect.recvListener 中的所有listenerWrapper处理。

而 connect.recvListener 中的值是通过 connect.addPacketListener() 方法添加的。


数据是从connect里来,处理还是由connect中的监听器处理,PacketReader 完成了数据流的转换和触发机制。


PacketReader 提供了触发机制和数据转换,除了数据转换需要处理数据外,触发机制并不涉及到任何的数据。

数据转换完毕之后,到底任何处理的呢?

在 ListenerWrapper 中!


触发的过程是读取 connection.recvListeners.values() 然后遍历执行其中的 ListenerWrapper 实例的notifyListener()方法。

connection.recvListeners.values()是通过 connect.addPacketListener() 添加数据的,


[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public void addPacketListener(PacketListener packetListener, PacketFilter packetFilter) {  
  2.     if (packetListener == null) {  
  3.         throw new NullPointerException("Packet listener is null.");  
  4.     }  
  5.     ListenerWrapper wrapper = new ListenerWrapper(packetListener, packetFilter);  
  6.     recvListeners.put(packetListener, wrapper);  
  7. }  

触发机制是通过传递 packet 给通过   addPacketListener()加入到列表中的所有(可以有多个) listenter .


遍历调用的方法:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public void notifyListener(Packet packet) {  
  2.            if (packetFilter == null || packetFilter.accept(packet)) {  
  3.                packetListener.processPacket(packet);  
  4.            }  
  5.        }  


触发机制是通过传递 packet 给  connection.recvListeners 列表中的所有 listenter 和 filter,

按先后顺序调用 filter.accept() 和 processPacket() 方法 .



 connection.recvListeners 是通过 addPacketListener()加入Listener和filter的。

只要通过addPacketListener()加入我们的listener和filter,就能够处理 packet 数据,实现自己的业务逻辑!


数据分发机制:

所有的 packet 被分发到每个listener中,并且各个listener互不影响。



所有的listenser 都实现了 PacketListener 接口,这个接口只有一个方法: 


public void processPacket(Packet packet);


通过查找继承这个接口的子类,可以看到 n多对packet 处理的方法,非常值得学习。

下面是一些子类,更多的是匿名类。


[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //处理 Message   
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.    PacketFilter typeFilter = new PacketTypeFilter(Message.class);  
  2.   
  3.     connection.addPacketListener(new PacketListener() {  
  4.         public void processPacket(Packet packet) {  
  5.             handlePacket(packet);  
  6.         }  
  7.     }, typeFilter);  
  8. }  

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //处理文件上传的   
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.     connection.addPacketListener(new PacketListener() {  
  2.         public void processPacket(Packet packet) {  
  3.             fireNewRequest((StreamInitiation) packet);  
  4.         }  
  5.     }, new AndFilter(new PacketTypeFilter(StreamInitiation.class),  
  6.             new IQTypeFilter(IQ.Type.SET)));  
  7. }  
  8.    

//处理多人聊天的

......


补充:


举个接受Message消息的例子:


[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //创建一个Message typeFilter   
  2. PacketFilter messageFilter = new PacketTypeFilter(Message.class);  
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.   
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //创建一个message listener  
  2. PacketListener messageListener = new PacketListener() {  
  3. public void processPacket(Packet packet) {  
  4. System.out.println("*** handle message packet ");  
  5. }  
  6. };  
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //加入列表  
  2. connection.addPacketListener(messageListener, messageFilter);  
  3.    
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. 现在运行起来就可以在messageListener里处理Message的业务逻辑了。  



总结:


只要继承 PacketListener接口,实现自己的 pakcetListener,并通过connect.addListener()加入监听队列,

这个packetListener就可以在processPacket方法中得到packet ,进行自己的逻辑处理。




http://blog.csdn.net/teamlet/article/details/25613603

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值