前面说过, 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;

}

});


执行的是线程是:

newListenerNotification(packet);


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

这有点类似触发器。


执行的是什么呢?


 public void run() {
for (ListenerWrapper listenerWrapper : connection.recvListeners.values()) {
try {
listenerWrapper.notifyListener(packet);
} catch (Exception e) {
System.err.println("Exception in packet listener: " + e);
e.printStackTrace();
}
}
}


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

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


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


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

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

ListenerWrapper 中!


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

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


     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);    } 

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


遍历调用的方法:

  public void notifyListener(Packet packet) {            if (packetFilter == null || packetFilter.accept(packet)) {                packetListener.processPacket(packet);            }        } 


触发机制是通过传递 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 处理的方法,非常值得学习。

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


//处理 Message 
        PacketFilter typeFilter = new PacketTypeFilter(Message.class);        connection.addPacketListener(new PacketListener() {            public void processPacket(Packet packet) {                handlePacket(packet);            }        }, typeFilter);    } 

//处理文件上传的
connection.addPacketListener(new PacketListener() {public void processPacket(Packet packet) {fireNewRequest((StreamInitiation) packet);}}, new AndFilter(new PacketTypeFilter(StreamInitiation.class),new IQTypeFilter(IQ.Type.SET)));}  

//处理多人聊天的

......


补充:


举个接受Message消息的例子:


//创建一个Message typeFilter PacketFilter messageFilter = new PacketTypeFilter(Message.class);
 
//创建一个message listenerPacketListener messageListener = new PacketListener() {public void processPacket(Packet packet) {System.out.println("*** handle message packet ");}};
//加入列表connection.addPacketListener(messageListener, messageFilter); 
现在运行起来就可以在messageListener里处理Message的业务逻辑了。



总结:


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

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







更多相关文章

  1. 将数据从java类传递到Web View html
  2. 【Android Developers Training】 82. 序言:传输数据时减少对电池
  3. 检查ArrayList是否只包含null值的方法。
  4. studio更新时候,不小心点了ignore,无法更新的解决方法
  5. android之发送短信的方法研究
  6. SQLite的Android光标在方法调用时崩溃
  7. android 2D 游戏的开发的方法
  8. Android中复杂Json数据的解析
  9. 在Skobbler中完成导航时,确定“街边”的最佳方法是什么?

随机推荐

  1. C语言中用户标识符的命名规则是什么
  2. C语言中 gets 和 getchar 区别?
  3. int占几个字节(c语言)?
  4. C语言中exit(0)和exit(1)有什么区别
  5. C语言中用户标识符是什么?
  6. 简述分配器的作用是什么?
  7. 如何使用c语言中的strlen()函数
  8. c语言中putchar()的功能是什么?
  9. C语言中 & 是什么意思?
  10. 成员函数可以重载吗?