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));
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 ,进行自己的逻辑处理。
更多相关文章
- 将数据从java类传递到Web View html
- 【Android Developers Training】 82. 序言:传输数据时减少对电池
- 检查ArrayList是否只包含null值的方法。
- studio更新时候,不小心点了ignore,无法更新的解决方法
- android之发送短信的方法研究
- SQLite的Android光标在方法调用时崩溃
- android 2D 游戏的开发的方法
- Android中复杂Json数据的解析
- 在Skobbler中完成导航时,确定“街边”的最佳方法是什么?