aSmack源码分析register过程分析

来源:互联网 发布:java移植安卓游戏 编辑:程序博客网 时间:2024/05/20 00:37

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);        }    }    
复制代码

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

0 0
原创粉丝点击