zoukankan      html  css  js  c++  java
  • 基于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);
            }
        }    

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

  • 相关阅读:
    [例程]string.trim().length()的用法
    用各种look and feel打造swing界面
    深入浅出Java多线程(1)方法 join
    eclipse中cvs使用配置
    什么时候用Vector, 什么时候改用ArrayList?
    array,vertor,arraylist,hashable,hashmap等几个易混淆概念的区别
    java.lang.Class.getResource()这哥个方法主要是做什么用
    织梦dedecms实现按照字母搜索的实现方法
    浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值
    用java –jar 命令运行Jar包
  • 原文地址:https://www.cnblogs.com/rioder/p/2876630.html
Copyright © 2011-2022 走看看