Smack PacketReader 監聽器啓動過程分析


Smack PacketReader 監聽器啓動過程分析


一、數據進入線程池


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客戶端 用戶註冊的部分代碼:


[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. PacketFilter packetFilter = new AndFilter(new PacketIDFilter(registration.getPacketID()), new PacketTypeFilter(IQ.class));  
  2.   
  3. PacketListener packetListener = new PacketListener() {  
  4.              
  5.          public void processPacket(Packet packet) {  
  6.               if (packet instanceof IQ) {  
  7.                   IQ response = (IQ) packet;  
  8.                   if (response.getType() == IQ.Type.ERROR) {  
  9.                        if (!response.getError().toString().contains("409")) {  
  10.                             Log.e(LOGTAG, "Unknown error while registering XMPP account! " + response.getError().getCondition());  
  11.                        }  
  12.                   } else if (response.getType() == IQ.Type.RESULT) {  
  13.                        xmppManager.setUsername(newUsername);  
  14.                        xmppManager.setPassword(newPassword);  
  15.                        Editor editor = sharedPrefs.edit();  
  16.                        editor.putString(Constants.XMPP_USERNAME, newUsername);  
  17.                        editor.putString(Constants.XMPP_PASSWORD, newPassword);  
  18.                        editor.commit();  
  19.                        Log.i(LOGTAG, "Account registered successfully");  
  20.                        xmppManager.runTask();  
  21.                  }  
  22.             }  
  23.         }  
  24. };  
  25.   
  26. connection.addPacketListener(packetListener, packetFilter);  
  27.     


五、監聽機制


只要在調用connect.setPacke等通訊方法的時候,就要先調用 connect.addPacketListener ,將 PacketListener 和 PacketFilter封裝在ListenerWrapper中,保存在隊列中。

listenerWrapper通過調用 nofityListener() 方法,啓動監聽事件。


[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1.     
  2.     
  3. protected static class ListenerWrapper {  
  4.   
  5.         private PacketListener packetListener;  
  6.         private PacketFilter packetFilter;  
  7.   
  8.         /** 
  9.          * Create a class which associates a packet filter with a listener. 
  10.          *  
  11.          * @param packetListener the packet listener. 
  12.          * @param packetFilter the associated filter or null if it listen for all packets. 
  13.          */  
  14.         public ListenerWrapper(PacketListener packetListener, PacketFilter packetFilter) {  
  15.             this.packetListener = packetListener;  
  16.             this.packetFilter = packetFilter;  
  17.         }  
  18.   
  19.         /**  
[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1.  * Notify and process the packet listener if the filter matches the packet.  
  2.  *   
  3.  * @param packet the packet which was sent or received.  
  4.  */  
  5. public void notifyListener(Packet packet) {  
  6.     if (packetFilter == null || packetFilter.accept(packet)) {  
  7.         packetListener.processPacket(packet);  
  8.     }  
  9. }  


notifyListener()方法調用自己封裝的 filter和listener 的方法。

首先檢查 packetFilter 並調用 packetFilter.accept()

然後執行packetListener.processPacket()


這兩個類和方法都是在第四步設置的,在這裏可以定義自己的邏輯處理數據。


總結:

本篇中,通過 packetFilter設置的 PacketTypeFilter 會影響對不同數據的處理。




轉:http://blog.csdn.net/teamlet/article/details/25431155

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章