基于XMPP协议的aSmack源码分析【3】register过程分析

register过程分析
RegisterTask这个task在运行中,添加了一个监听,上面说道的PacketReader中有一个消息机制,在不停的解析服务器返回的结果,然后将解析过后的包分发给各个监听器(观察者),而register中就注册了一个监听器,比较有意思的是,监听器被注册时还加了一个过滤器,这个过滤器的目的是监听器只接收自己感兴趣的内容,这个设计真的很赞。这样就不必在数据源头PacketReader中对数据进行过滤了,只要后期扩展自己Packet和自己的过滤器,就能达到排除自己不关心的信息的功能。

1 Registration registration = new Registration();

2 

3                 PacketFilter packetFilter = new AndFilter(new PacketIDFilter(

4                         registration.getPacketID()), new PacketTypeFilter(

5                         IQ.class));

其中Registration的类型其实一个IQ的子类,IQ是Packet的子类。
AndFilter是PacketFilter的子类,PacketFilter的种类型有很多,也可以自己扩展,AndFilter就是其中一个、PacketTypeFilter也是、PacketIDFilter也是,
其中PacketTypeFilter的构造方法传入一个IQ.class,其实就是通过这个类文件来过滤packet,这个PacketTypeFilter就是要设置关心的Packet,这里面它告诉监听器,只接收类型为IQ的Packet,这些Filter中都有一个关键方法,accept(Packet packet).这个accept方法每个Filter的实现方式都不一样,我们可可以扩展自己的Filter并且重写这个方法,最有意思的是AndFilter这个类,他的构造方法传入的是一个动态数组,类型为PacketFilter,你可以传入你需要的过滤器,将他们当成组合条件使用来过滤Packet,这个就是典型的装饰设计模式和职责链模式的组合使用。

注册监听器

PacketListener packetListener = new PacketListener() {

                    //这一部分就是监听器接收到Packet后执行的后续操作

                    public void processPacket(Packet packet) {

                        Log.d("RegisterTask.PacketListener",

                                "processPacket().....");

                        Log.d("RegisterTask.PacketListener", "packet="

                                + packet.toXML());



                        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);

                                Log.d(LOGTAG, "username=" + newUsername);

                                Log.d(LOGTAG, "password=" + 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");

                                //执行task

                                xmppManager.runTask();

                            }

                        }

                    }

                };



                connection.addPacketListener(packetListener, packetFilter);

addPacketListener方法传入一个监听器和过滤器,看一下内部

/**

     * Registers a packet listener with this connection. A packet filter determines

     * which packets will be delivered to the listener. If the same packet listener

     * is added again with a different filter, only the new filter will be used.

     * 

     * @param packetListener the packet listener to notify of new received packets.

     * @param packetFilter   the packet filter to use.

     */

    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);

    }

可以看到,监听器和过滤器被 ListenerWrapper 再次封装,后续的recvListeners这个集合将ListenerWrapper收入囊中,好整个注册过程完毕,就等待接收信息了,那么发送信息的地方在什么地方呢?分析connect过程时,上面的PacketReader中已经开始循环发送了,代码如下
listenerExecutor.submit(new ListenerNotification(packet));其中ListenerNotification是个Runnable

/**

     * 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() {

            for (ListenerWrapper listenerWrapper : connection.recvListeners.values()) {

                listenerWrapper.notifyListener(packet);

            }

        }

    }

而listenerWrapper的notifyListener(packet)内部,使用了传入的过滤器对Packet进行了过滤

/**

         * 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);

            }

而具体的过滤机制还是转调了传入的过滤器本身的过滤方式accept,非常的灵活。过滤完的Packet将被发送出去

这个方法connection.sendPacket(registration);将一个Registration对象发了出去,

public void sendPacket(Packet packet) {

        if (!isConnected()) {

            throw new IllegalStateException("Not connected to server.");

        }

        if (packet == null) {

            throw new NullPointerException("Packet is null.");

        }

        packetWriter.sendPacket(packet);

    }

内部转调的是 packetWriter.sendPacket(packet);以前提到过PacketWirter中有两个循环机制,其中一个就是在不停的访问队列来获取Packet,而这个sendPacket方法就是将消息写入队列中供消费者使用。

/**

     * Sends the specified packet to the server.

     *

     * @param packet the packet to send.

     */

    public void sendPacket(Packet packet) {

        if (!done) {

            // Invoke interceptors for the new packet that is about to be sent. Interceptors

            // may modify the content of the packet.

            //内部执行了一个发送数据源的动作,也是为某些监听器对象服务的interceptorWrapper.notifyListener(packet);

            connection.firePacketInterceptors(packet);



            try {

                //将一个Packet对象放入到阻塞队列中,在上面的witerPacket方法中的wile循环中发送出去

                queue.put(packet);

            }

            catch (InterruptedException ie) {

                ie.printStackTrace();

                return;

            }

            synchronized (queue) {

                queue.notifyAll();

            }



            // Process packet writer listeners. Note that we're using the sending

            // thread so it's expected that listeners are fast.

            connection.firePacketSendingListeners(packet);

        }

    }    

其实,注册的过程就是在注册监听,这样在有消息发出时,才可以根据业务需求对消息进行接收和处理。

你可能感兴趣的:(smack)