前面说过, PacketReader 在构造函数中传递 XmppConnection的实例,并赋给自己的成员变量 connect;
又启动了一个 readerThread 线程,在 parsePackets() 方法中处理connect的输入数据流 (也就是socket的数据输入流)。
这时读入的数据是xml格式的(格式说明参见 Xmpp协议),
parsePackets()方法负责将xml数据转换为java对象,
转换为java对象后,parsePackets() 调用 processPacket()方法处理传入的Java对象。
processPacket()方法将传入的Java对象传递个另一个线程由另一线程来处理。
线程切换的语句:
listenerExecutor.submit(new ListenerNotification(packet));
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 处理。
这有点类似触发器。
执行的是什么呢?
- 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 listener
- PacketListener 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 ,进行自己的逻辑处理。
http://blog.csdn.net/teamlet/article/details/25613603