smack 源码分析- PacketReader (android上实现长连接)

smack 源码分析- PacketWriter (android上实现长连接) 介绍完PacketWriter 之后, 接下来分析PacketReader. PacketReader的作用主要用来接收云端推送的消息并解析然后调用相应的监听器完成相关的操作.

什么都别说, 先看代码:

 

//构造函数
protected PacketReader(final XMPPConnection connection) {
        this.connection = connection;
        this.init();
}


 /**
     * Initializes the reader in order to be used. The reader is initialized
     * during the first connection and when reconnecting due to an abruptly
     * disconnection.
     */
    protected void init() {
        done = false;
        connectionID = null;

        //开辟一个线程, 解析收到的数据包
        readerThread = new Thread() {
            public void run() {
                parsePackets(this);
            }
        };
        readerThread.setName("Smack Packet Reader (" + connection.connectionCounterValue + ")");
        readerThread.setDaemon(true);

        // Create an executor to deliver incoming packets to listeners. We'll
        // use a single
        // thread with an unbounded queue.
        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;
            }
        });

        resetParser();
    }




 /**
     * Parse top-level packets in order to process them further.
     * 
     * @param thread the thread that is being used by the reader to parse
     *            incoming packets.
     */
    private void parsePackets(Thread thread) {
        try {
            int eventType = parser.getEventType();
            do {

                if (eventType == XmlPullParser.START_TAG) {
                    if (parser.getName().equals("message")) {
                        processPacket(PacketParserUtils.parseMessage(parser));
                    } else if (parser.getName().equals("iq")) {
                        processPacket(PacketParserUtils.parseIQ(parser, connection));
                    } else if (parser.getName().equals("presence")) {
                        processPacket(PacketParserUtils.parsePresence(parser));
                    }

 

构造函数和init()方法PacketWriter一样, 不多说了. 直接看parsePackets(). 在parsePackets()是直接调用processPacket()方法解析, 我们再来看processPacket()方法:

 

/**
     * Processes a packet after it's been fully parsed by looping through the
     * installed packet collectors and listeners and letting them examine the
     * packet to see if they are a match with the filter.
     * 
     * @param packet the packet to process.
     */
    private void processPacket(Packet packet) {
        if (packet == null) {
            return;
        }

        // Loop through all collectors and notify the appropriate ones.
        for (PacketCollector collector : connection.getPacketCollectors()) {
            collector.processPacket(packet);
        }

        // Deliver the incoming packet to listeners.
        listenerExecutor.submit(new ListenerNotification(packet));
    }

 

在processPacket()的最后一行是通过ExecutorService类型的一个listenerExecutor实例执行一个线程ListenerNotification完成的. 接下来: 

 

 /**
     * A runnable to notify all listeners of a packet.
     */
    private class ListenerNotification implements Runnable {

        private Packet packet;

        public ListenerNotification(Packet packet) {
            this.packet = packet;
        }

        public void run() {
        	//循环读取注册了的监听器并通知处理packet
            for (ListenerWrapper listenerWrapper : connection.recvListeners.values()) {
            	
                listenerWrapper.notifyListener(packet);
            }
        }
    }

 

在ListenerNotification的run方法中,  是循环读取connection.recvListeners.values()获取ListenerWrapper .

那么ListenerWrapper 是什么呢? 我们首先来看这里connection.recvListeners.values(), 这connection实际上

是一个XMPPConnection的一个实例, 而XMPPConnection继承了Connection, recvListeners实际上是Connection

的一个成员变量. 然后再来看ListenerWrapper类:

/**
     * A wrapper class to associate a packet filter with a listener.
     *
     */
    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);
            }
        }
    }
 

ListenerWrapper类实际上是一个包装类, 该类的作用是将packetListener 和packetFilter关联在一起. 那么

packetListener 和packetFilter分别是什么嗯, 查看smack帮助文档可知:


Smack提供灵活的框架来通过两种构造处理收到的 packet:

  • org.jivesoftware.smack.PacketCollector —— 一个让您同步等待新packet的类。
  • org.jivesoftware.smack.PacketListener —— 一个异步通知您引入的packet的接口。

packet监听器用于事件样式的编程,而packet收集器有一个可以做轮询和阻塞操作的packet的结果队列。 所以, 当您想对一个有可能随时到来的packet采取一些操作时,使用packet监听器;而当您想等待一个特别的packet到来 时,使用packet收集器。您可以使用XMPPConnection实例创建packet收集器和监听器。

org.jivesoftware.smack.filter.PacketFilter 接口决定哪个特别的将会被传递 PacketCollectorPacketListener。org.jivesoftware.smack.filter package包中有许多预定义的过滤器。


packetListener 是一个能够处理随时可能到了的packet监听器, packetFilter能够判断packet是否由该packetListener处理

是的话则调用processPacket()方法处理packet. 至此整个过程处理完成

 

 

Smack是一个开源的XMPP客户端库,可用于在Android平台上构建即时通信应用程序。在使用SmackAndroid应用程序中,需要使用Smack-Android库来处理网络和连接管理。 以下是一个简单的示例代码,演示如何使用Smack-Android库连接到XMPP服务器并发送消息: 1. 添加依赖库 在项目的build.gradle文件中添加以下依赖: ``` dependencies { implementation 'org.igniterealtime.smack:smack-android-extensions:4.4.0' implementation 'org.igniterealtime.smack:smack-tcp:4.4.0' } ``` 2. 初始化连接 在应用程序启动时,需要初始化XMPPConnection对象,并且连接到XMPP服务器。 ``` XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder() .setUsernameAndPassword("username", "password") .setXmppDomain("example.com") .setHost("xmpp.example.com") .setPort(5222) .setSecurityMode(ConnectionConfiguration.SecurityMode.required) .build(); XMPPTCPConnection connection = new XMPPTCPConnection(config); try { connection.connect(); connection.login(); // Connection successful } catch (SmackException | IOException | XMPPException e) { e.printStackTrace(); // Connection failed } ``` 3. 发送消息 连接成功后,可以使用XMPPConnection对象发送消息。 ``` ChatManager chatManager = ChatManager.getInstanceFor(connection); Chat chat = chatManager.createChat("recipient@example.com"); try { chat.sendMessage("Hello, World!"); } catch (SmackException.NotConnectedException | InterruptedException e) { e.printStackTrace(); } ``` 这是一个简单的Smack-Android示例,用于连接到XMPP服务器并发送消息。当然,在实际应用程序中可能需要更多的功能和处理,但这个示例提供了一个入门的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值