一、數據進入線程池
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客戶端 用戶註冊的部分代碼:
- 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() 方法,啓動監聽事件。
- 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;
- }
- /**
- * 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