欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android即时通讯技术基于XMPP协议asmack聊天功能实战

程序员文章站 2022-07-13 14:40:53
...

XMPP协议简介

XMPP协议(Extensible Messaging and PresenceProtocol,可扩展消息处理现场协议)是一种基于XML的协议,目的是为了解决及时通信标准而提出来的,最早是在Jabber上实现的。它继承了在XML环境中灵活的发展性。因此,基于XMPP的应用具有超强的可扩展性。并且XML很易穿过防火墙,所以用XMPP构建的应用不易受到防火墙的阻碍。利用XMPP作为通用的传输机制,不同组织内的不同应用都可以进行有效的通信。

这篇文章有基本的介绍,http://blog.csdn.net/xutaozero21/article/details/4873439

IM

Instant Messenger,及时通信软件,就是大家使用的QQ、MSN Messenger和Gtalk等等。其中Gtalk 就是基于XMPP 协议的一个实现,其他的则不是。当前IM 几乎作为每个上网者必然使用的工具,在国外的大型企业中有一些企业级的IM应用,但是其商业价值还没完全发挥出来。设想既然XMPP 协议是一个公开的协议,那么每个企业都可以利用它来开发适合本身企业工作,提高自身生产效率的IM;甚至,你还可以在网络游戏中集成这种通信软件,不但让你可以边游戏边聊天,也可以开发出适合游戏本身的IM 应用,比如说一些游戏关键场景提醒功能,团队语音交流等等都可以基于IM来实现。

 

本文主要讲解在android使用xmpp协议进行即时通信,所涉及3个主要的东西,它们是openfire、smack和spark,这个三个东东结合起来就是完整的xmpp IM实现,这里简单介绍一下这3个东东在下文的作用:

openfire主要是作为服务器,负责管理客户端的通信连接,以及提供客户端一些通信信息和连接信息。

Smack主要是xmpp协议的实现,提供了一套很好的api,所以下面操作xmpp都是通过使用smack的api来实现,当然因为是在android里,所以使用的是asmack这个包,里面方法跟smack包差不多。

Spark 是IM客户端的实现,其实就是使用了smack 的api实现的。

 

下图展示了三者之间的关系:(很明显这个图是偷别人的,具体是哪里我忘了,因为资料都是复制到文档后慢慢研究看的)

android即时通讯技术基于XMPP协议asmack聊天功能实战

从图上可以了解到,client 端和server端都可以通过插件的方式来进行扩展,smack是二者传递数据的媒介。

 

配置openfire服务器

具体步骤请移步:http://javatech.blog.163.com/blog/static/1766322992010111725339587/

配置成功如果以后ip地址变了,那肯定又是开不了,解决办法请移步:http://blog.csdn.net/HappySheepherder/article/details/4707124

配置成功后,在服务器创建一个简单的用户来测试,然后安装spark,设置好服务器的ip与端口,使用刚才创建的用户登录,登录OK说明服务器成功搭建。

Android IM功能(因为是测试demo,因此界面超级简陋,代码都是给出重要的一部分,剩余的可以在最后下面项目查看)

 

配置要求

android 2.2、 asmack-jse.jar、myeclipse

连接服务器

在打开软件后会开始初始化,完成与openfire服务器的连接,设置一些配置

static {
        XMPPConnection.DEBUG_ENABLED = true;
        final ConnectionConfiguration connectionConfig = new ConnectionConfiguration(
                host, 5222, "");
        // Google talk
        // ConnectionConfiguration connectionConfig = new
        // ConnectionConfiguration(
        // "talk.google.com", 5222, "gmail.com");{
        XMPPConnection.DEBUG_ENABLED = true;
        final ConnectionConfiguration connectionConfig = new ConnectionConfiguration(
                host, 5222, "");
        // Google talk
        // ConnectionConfiguration connectionConfig = new
        // ConnectionConfiguration(
        // "talk.google.com", 5222, "gmail.com");
        // connectionConfig.setSASLAuthenticationEnabled(false);
        ActivityMain.connection = new XMPPConnection(connectionConfig);

        ActivityMain.connection.DEBUG_ENABLED = true;

        ProviderManager pm = ProviderManager.getInstance();
        configure(pm);
    }

ActivityMain.connection = new XMPPConnection(connectionConfig);

        ActivityMain.connection.DEBUG_ENABLED = true;

        ProviderManager pm = ProviderManager.getInstance();
        configure(pm);
    }

注册模块

注册有两种方法:一种是用createAccount ,不过我测试了一下发现不能创建用户,具体原因不详,下面介绍第二种。

android即时通讯技术基于XMPP协议asmack聊天功能实战

如上图:注册成功后服务器将多了ggg用户。

具体实现如下:

Registration reg = new Registration();
                reg.setType(IQ.Type.SET);
                reg.setTo(ConnectionSingleton.getInstance().getServiceName());
                reg.setUsername(username.getText().toString());
                reg.setPassword(password.getText().toString());
                reg.addAttribute("android", "geolo_createUser_android");
                System.out.println("reg:" + reg);
                PacketFilter filter = new AndFilter(new PacketIDFilter(reg
                        .getPacketID()), new PacketTypeFilter(IQ.class));
                PacketCollector collector = ConnectionSingleton.getInstance()
                        .createPacketCollector(filter);
                ConnectionSingleton.getInstance().sendPacket(reg);
                
                result = (IQ) collector.nextResult(SmackConfiguration
                        .getPacketReplyTimeout());
                // Stop queuing results
                collector.cancel();
                 if (result == null) {
                    Toast.makeText(getApplicationContext(), "服,
                            Toast.LENGTH_SHORT).show();
                } else if (result.getType() == IQ.Type.ERROR) {
                    if (result.getError().toString().equalsIgnoreCase(
                            "conflict(409)")) {
                        Toast.makeText(getApplicationContext(), "这,
                                Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(getApplicationContext(), "注,
                                Toast.LENGTH_SHORT).show();
                    }
                } else if (result.getType() == IQ.Type.RESULT) {
                    Toast.makeText(getApplicationContext(), "恭,
                            Toast.LENGTH_SHORT).show();
                }new Registration();
                reg.setType(IQ.Type.SET);
                reg.setTo(ConnectionSingleton.getInstance().getServiceName());
                reg.setUsername(username.getText().toString());
                reg.setPassword(password.getText().toString());
                reg.addAttribute("android", "geolo_createUser_android");
                System.out.println("reg:" + reg);
                PacketFilter filter = new AndFilter(new PacketIDFilter(reg
                        .getPacketID()), new PacketTypeFilter(IQ.class));
                PacketCollector collector = ConnectionSingleton.getInstance()
                        .createPacketCollector(filter);
                ConnectionSingleton.getInstance().sendPacket(reg);
                
                result = (IQ) collector.nextResult(SmackConfiguration
                        .getPacketReplyTimeout());
                // Stop queuing results
                collector.cancel();
                 if (result == null) {
                    Toast.makeText(getApplicationContext(), "服,
                            Toast.LENGTH_SHORT).show();
                } else if (result.getType() == IQ.Type.ERROR) {
                    if (result.getError().toString().equalsIgnoreCase(
                            "conflict(409)")) {
                        Toast.makeText(getApplicationContext(), "这,
                                Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(getApplicationContext(), "注,
                                Toast.LENGTH_SHORT).show();
                    }
                } else if (result.getType() == IQ.Type.RESULT) {
                    Toast.makeText(getApplicationContext(), "恭,
                            Toast.LENGTH_SHORT).show();
                }

使用注册类,设置好注册的用户名密码和一些属性字段,直接设置包过滤,根据这个过滤创建一个结果集合,发送注册信息包,等待获取结果,剩余就是判断结果内容.

 

登录模块

登录比较简单

ConnectionSingleton.getInstance().connect();// connect
String account = etUsername.getText().toString();
String password = etPassword.getText().toString();
// 保存用户和密码// connect
String account = etUsername.getText().toString();
String password = etPassword.getText().toString();
// 保存用户和密码
ActivityLogin.util.saveString(ACCOUNT_KEY, account);
ActivityLogin.util.saveString(PASSWORD_KEY, password);
ConnectionSingleton.getInstance().login(account, password);// login

// login success 
System.out.println("login success");
ActivityLogin.mCurrentAccount = account;
System.out.println(ConnectionSingleton.getInstance()
        .getUser());
// 登录成功后发现在线状态util.saveString(ACCOUNT_KEY, account);
ActivityLogin.util.saveString(PASSWORD_KEY, password);
ConnectionSingleton.getInstance().login(account, password);// login

// login success 
System.out.println("login success");
ActivityLogin.mCurrentAccount = account;
System.out.println(ConnectionSingleton.getInstance()
        .getUser());
// 登录成功后发现在线状态
Presence presence = new Presence(Presence.Type.available);
ConnectionSingleton.getInstance().sendPacket(presence);

// 开始主界面new Presence(Presence.Type.available);
ConnectionSingleton.getInstance().sendPacket(presence);

// 开始主界面
Intent intent = new Intent(ActivityLogin.this,
        ActivityMain.class);
startActivity(intent);
new Intent(ActivityLogin.this,
        ActivityMain.class);
startActivity(intent);

 

获取联系人模块(ActivityMain 主界面)

获取联系人并将相关信息保存到一个list数组里,最后通知listview更新界面

roster = ActivityMain.connection.getRoster();
= ActivityMain.connection.getRoster();
 
public void updateRoster() {
        Collection<RosterEntry> entries = roster.getEntries();
        for (RosterEntry entry : entries) {
            System.out.print(entry.getName() + " - " + entry.getUser() + " - "
                    + entry.getType() + " - " + entry.getGroups().size());
            Presence presence = roster.getPresence(entry.getUser());
            System.out.println(" - " + presence.getStatus() + " - "
                    + presence.getFrom());
            User user = new User();
            user.setName(entry.getName());
            user.setUser(entry.getUser());
            user.setType(entry.getType());
            user.setSize(entry.getGroups().size());
            user.setStatus(presence.getStatus());
            user.setFrom(presence.getFrom());
            userinfos.add(user);
        }
        rosterAdapter.notifyDataSetChanged();
    }updateRoster() {
        Collection<RosterEntry> entries = roster.getEntries();
        for (RosterEntry entry : entries) {
            System.out.print(entry.getName() + " - " + entry.getUser() + " - "
                    + entry.getType() + " - " + entry.getGroups().size());
            Presence presence = roster.getPresence(entry.getUser());
            System.out.println(" - " + presence.getStatus() + " - "
                    + presence.getFrom());
            User user = new User();
            user.setName(entry.getName());
            user.setUser(entry.getUser());
            user.setType(entry.getType());
            user.setSize(entry.getGroups().size());
            user.setStatus(presence.getStatus());
            user.setFrom(presence.getFrom());
            userinfos.add(user);
        }
        rosterAdapter.notifyDataSetChanged();
    }
 

单人聊天模块

第一次修改:

在主界面点击选择一个用户,进入聊天Activity,ActivityChat先获取传过来的用户,创建聊天类并对该用户设置消息监听

ChatManager chatmanager = ConnectionSingleton.getInstance()
                .getChatManager();

        // get user
        Intent intent = getIntent();
        String user = intent.getStringExtra("user");
        System.out.println("user:" + user);
        // new a session
        newChat = chatmanager.createChat(user, null);
        // 监听聊天消息// get user
        Intent intent = getIntent();
        String user = intent.getStringExtra("user");
        System.out.println("user:" + user);
        // new a session
        newChat = chatmanager.createChat(user, null);
        // 监听聊天消息
        chatmanager.addChatListener(new ChatManagerListenerEx());

        // send message
        try {
            newChat.sendMessage("im bird man");

        } catch (XMPPException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }new ChatManagerListenerEx());

        // send message
        try {
            newChat.sendMessage("im bird man");

        } catch (XMPPException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

监听类

public class ChatManagerListenerEx implements ChatManagerListener {

        @Override
        public void chatCreated(Chat chat, boolean arg1) {
            // TODO Auto-generated method stub
            chat.addMessageListener(ml);
        }

    }

    public class MessageListenerEx implements MessageListener {

        @Override
        public void processMessage(Chat arg0, Message message) {
            String result = message.getFrom() + ":" + message.getBody();
            System.out.println(result);
            android.os.Message msg = new android.os.Message();
            msg.what = 0;
            Bundle bd = new Bundle();
            bd.putString("msg", result);
            msg.setData(bd);
            handler.sendMessage(msg);

        }
    }
ChatManagerListenerEx implements ChatManagerListener {

        @Override
        public void chatCreated(Chat chat, boolean arg1) {
            // TODO Auto-generated method stub
            chat.addMessageListener(ml);
        }

    }

    public class MessageListenerEx implements MessageListener {

        @Override
        public void processMessage(Chat arg0, Message message) {
            String result = message.getFrom() + ":" + message.getBody();
            System.out.println(result);
            android.os.Message msg = new android.os.Message();
            msg.what = 0;
            Bundle bd = new Bundle();
            bd.putString("msg", result);
            msg.setData(bd);
            handler.sendMessage(msg);

        }
    }

 

所获取到的消息都是通过handler来更新UI

public Handler handler = new Handler() {

        @Override
        public void handleMessage(android.os.Message msg) {

            switch (msg.what) {
            case 0: {
                String result = msg.getData().getString("msg");
                record.setText(record.getText() + "\n" + result);
            }
                break;
            default:
                break;
            }
        }
    };Handler handler = new Handler() {

        @Override
        public void handleMessage(android.os.Message msg) {

            switch (msg.what) {
            case 0: {
                String result = msg.getData().getString("msg");
                record.setText(record.getText() + "\n" + result);
            }
                break;
            default:
                break;
            }
        }
    };

 

aaa跟bbb 的聊天

android即时通讯技术基于XMPP协议asmack聊天功能实战

android即时通讯技术基于XMPP协议asmack聊天功能实战

第二次修改:

第一次的测试,发现如果多个人之间都成为好友,那么他们之间的聊天就出现了接收不到的信息,当然在跟spark测试时,spark可以收到android端的信息,不过android客户端是收到这个信息,不过却没有显示出来,具体原因还不太清楚。因此在第二次修改我改成监听所有聊天信息包,然后再分析包的归属,分发到对应的聊天窗口。

android即时通讯技术基于XMPP协议asmack聊天功能实战

 

这里就是监听到包后打印的消息,打印出了jid和消息内容

public class XmppMessageManager implements ChatManagerListener {
        private XMPPConnection _connection;
        private ChatManager manager = null;

        public void initialize(XMPPConnection connection) {
            _connection = connection;
            manager = _connection.getChatManager();
            manager.addChatListener(this);
        }

        @Override
        public void chatCreated(Chat chat, boolean arg1) {
            // TODO Auto-generated method stub
            chat.addMessageListener(new MessageListener() {
                public void processMessage(Chat newchat, Message message) {
                    // 若是聊天窗口存在,将消息转往目前窗口
                    // 若窗口不存在,创建新的窗口
                    System.out
                            .println(message.getFrom() + ":" + message.getBody());

                    
                    if (!ActivityMain.chats.containsKey(message.getFrom())) {
                        ActivityMain.chats.put(message.getFrom(), newchat);
                    } else {

                    }

                }
            });
        }
    }XmppMessageManager implements ChatManagerListener {
        private XMPPConnection _connection;
        private ChatManager manager = null;

        public void initialize(XMPPConnection connection) {
            _connection = connection;
            manager = _connection.getChatManager();
            manager.addChatListener(this);
        }

        @Override
        public void chatCreated(Chat chat, boolean arg1) {
            // TODO Auto-generated method stub
            chat.addMessageListener(new MessageListener() {
                public void processMessage(Chat newchat, Message message) {
                    // 若是聊天窗口存在,将消息转往目前窗口
                    // 若窗口不存在,创建新的窗口
                    System.out
                            .println(message.getFrom() + ":" + message.getBody());

                    
                    if (!ActivityMain.chats.containsKey(message.getFrom())) {
                        ActivityMain.chats.put(message.getFrom(), newchat);
                    } else {

                    }

                }
            });
        }
    }

主要就是重写了ChatManagerListener类的监听,分发处理暂时没有想好怎么写。接着在后台启动service就可以开始监听,行了第一次修改那些可以去掉了^0^。

 

多人聊天模块

也是在主界面的菜单进入ActivityMultiChat,该界面显示所创建的房间,点击就跳转到ActivityMultiRoom 。

获取所有房间比较简单,只需执行下面这段代码

hostrooms = MultiUserChat.getHostedRooms(ActivityMain.connection,

"conference.zhanghaitao-pc");

跳转到后获取要加入的房间的jid,并创建监听。

jid = getIntent().getStringExtra("jid");

 

<span style="color:#00ff00"><span style="color:#3f7f5f">   //</span>后面服务名称必需是创建房间的那个服务</span>
   String multiUserRoom = jid;
    try {
        muc = new MultiUserChat(ActivityMain.connection, multiUserRoom);
        // 创建聊天室,进入房间后的nicknametry {
        muc = new MultiUserChat(ActivityMain.connection, multiUserRoom);
        // 创建聊天室,进入房间后的nickname
        muc.join(ActivityLogin.mCurrentAccount);

        Log.v(TAG, "join success");

    } catch (XMPPException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    ChatPacketListener chatListener = new ChatPacketListener(muc);
    muc.addMessageListener(chatListener);mCurrentAccount);

        Log.v(TAG, "join success");

    } catch (XMPPException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    ChatPacketListener chatListener = new ChatPacketListener(muc);
    muc.addMessageListener(chatListener);

 

监听大概的流程跟单人聊天差不多,都是handler来操作。不过多人聊天是重写了PacketListener。具体如下(不过该方法是监听房间的信息,也就是说显示的是以房间为名字的消息):

class ChatPacketListener implements PacketListener {
        private String _number;
        private Date _lastDate;
        private MultiUserChat _muc;
        private String _roomName;

        public ChatPacketListener(MultiUserChat muc) {
            _number = "0";
            _lastDate = new Date(0);
            _muc = muc;
            _roomName = muc.getRoom();
        }

        @Override
        public void processPacket(Packet packet) {
            Message message = (Message) packet;
            String from = message.getFrom();

            if (message.getBody() != null) {
                DelayInformation inf = (DelayInformation) message.getExtension(
                        "x", "jabber:x:delay");
                Date sentDate;
                if (inf != null) {
                    sentDate = inf.getStamp();
                } else {
                    sentDate = new Date();
                }

                Log.w(TAG, "Receive old message: date="
                        + sentDate.toLocaleString() + " ; message="
                        + message.getBody());

                android.os.Message msg = new android.os.Message();
                msg.what = RECEIVE;
                Bundle bd = new Bundle();
                bd.putString("from", from);
                bd.putString("body", message.getBody());
                msg.setData(bd);
                handler.sendMessage(msg);
            }
        }
    }ChatPacketListener implements PacketListener {
        private String _number;
        private Date _lastDate;
        private MultiUserChat _muc;
        private String _roomName;

        public ChatPacketListener(MultiUserChat muc) {
            _number = "0";
            _lastDate = new Date(0);
            _muc = muc;
            _roomName = muc.getRoom();
        }

        @Override
        public void processPacket(Packet packet) {
            Message message = (Message) packet;
            String from = message.getFrom();

            if (message.getBody() != null) {
                DelayInformation inf = (DelayInformation) message.getExtension(
                        "x", "jabber:x:delay");
                Date sentDate;
                if (inf != null) {
                    sentDate = inf.getStamp();
                } else {
                    sentDate = new Date();
                }

                Log.w(TAG, "Receive old message: date="
                        + sentDate.toLocaleString() + " ; message="
                        + message.getBody());

                android.os.Message msg = new android.os.Message();
                msg.what = RECEIVE;
                Bundle bd = new Bundle();
                bd.putString("from", from);
                bd.putString("body", message.getBody());
                msg.setData(bd);
                handler.sendMessage(msg);
            }
        }
    }

 

下载模块

在主界面对着用户名长按,进入下载activity。进入activityFileTransfer,点击传输按钮即可将文件传输给之前选择的用户,当然这里做得比较简单,并没有拒绝功能,一旦发现有文件就接受。

FileTransferManager transfer = new FileTransferManager(
                        ActivityMain.connection);
                String destination = user;
                OutgoingFileTransfer out = transfer
                        .createOutgoingFileTransfer(destination + "/Smack");
new FileTransferManager(
                        ActivityMain.connection);
                String destination = user;
                OutgoingFileTransfer out = transfer
                        .createOutgoingFileTransfer(destination + "/Smack");

那用户是如何监听到有文件并且接受呢?在进入主界面的时候就已经开始了一个service(fileListenerService),该服务创建文件的监听类(XmppFileManager),监听类主要继承FileTransferListener 重写里面的fileTransferRequest方法。

File saveTo;
        // set answerTo for replies and send()
        answerTo = request.getRequestor();
        if (!Environment.MEDIA_MOUNTED.equals(Environment
                .getExternalStorageState())) {
            send("External Media not mounted read/write");
            return;
        } else if (!landingDir.isDirectory()) {
            send("The directory " + landingDir.getAbsolutePath()
                    + " is not a directory");
            return;
        }
        saveTo = new File(landingDir, request.getFileName());
        if (saveTo.exists()) {
            send("The file " + saveTo.getAbsolutePath() + " already exists");
            // delete
            saveTo.delete();
            // return;
        }
        IncomingFileTransfer transfer = request.accept();
        send("File transfer: " + saveTo.getName() + " - "
                + request.getFileSize() / 1024 + " KB");
        try {
            transfer.recieveFile(saveTo);
            send("File transfer: " + saveTo.getName() + " - "
                    + transfer.getStatus());
            double percents = 0.0;
            while (!transfer.isDone()) {
                if (transfer.getStatus().equals(Status.in_progress)) {
                    percents = ((int) (transfer.getProgress() * 10000)) / 100.0;
                    send("File transfer: " + saveTo.getName() + " - "
                            + percents + "%");
                } else if (transfer.getStatus().equals(Status.error)) {
                    send(returnAndLogError(transfer));
                    return;
                }
                Thread.sleep(1000);
            }
            if (transfer.getStatus().equals(Status.complete)) {
                send("File transfer complete. File saved as "
                        + saveTo.getAbsolutePath());
            } else {
                send(returnAndLogError(transfer));
            }
        } catch (Exception ex) {
            String message = "Cannot receive the file because an error occured during the process."
                    + ex;
            Log.e(TAG, message, ex);
            send(message);
        }// set answerTo for replies and send()
        answerTo = request.getRequestor();
        if (!Environment.MEDIA_MOUNTED.equals(Environment
                .getExternalStorageState())) {
            send("External Media not mounted read/write");
            return;
        } else if (!landingDir.isDirectory()) {
            send("The directory " + landingDir.getAbsolutePath()
                    + " is not a directory");
            return;
        }
        saveTo = new File(landingDir, request.getFileName());
        if (saveTo.exists()) {
            send("The file " + saveTo.getAbsolutePath() + " already exists");
            // delete
            saveTo.delete();
            // return;
        }
        IncomingFileTransfer transfer = request.accept();
        send("File transfer: " + saveTo.getName() + " - "
                + request.getFileSize() / 1024 + " KB");
        try {
            transfer.recieveFile(saveTo);
            send("File transfer: " + saveTo.getName() + " - "
                    + transfer.getStatus());
            double percents = 0.0;
            while (!transfer.isDone()) {
                if (transfer.getStatus().equals(Status.in_progress)) {
                    percents = ((int) (transfer.getProgress() * 10000)) / 100.0;
                    send("File transfer: " + saveTo.getName() + " - "
                            + percents + "%");
                } else if (transfer.getStatus().equals(Status.error)) {
                    send(returnAndLogError(transfer));
                    return;
                }
                Thread.sleep(1000);
            }
            if (transfer.getStatus().equals(Status.complete)) {
                send("File transfer complete. File saved as "
                        + saveTo.getAbsolutePath());
            } else {
                send(returnAndLogError(transfer));
            }
        } catch (Exception ex) {
            String message = "Cannot receive the file because an error occured during the process."
                    + ex;
            Log.e(TAG, message, ex);
            send(message);
        }

 断线重连

try {
                    Class.forName("org.jivesoftware.smack.ReconnectionManager");
                } catch (Exception e1) {
                }  

ConnectionConfiguration configuration = new ConnectionConfiguration(
                Contents.HOST, Contents.PORT);
        configuration.setReconnectionAllowed(true);

connection.connect();
if (connection.isConnected()) {
                        
connection.addConnectionListener(connectionListener);
                        
                    }
 
 
public static ConnectionListener connectionListener = new ConnectionListener() {
 
        @Override
        public void reconnectionSuccessful() {
            Log.i("connection", "reconnectionSuccessful");
        }
 
        @Override
        public void reconnectionFailed(Exception arg0) {
            Log.i("connection", "reconnectionFailed");
        }
 
        @Override
        public void reconnectingIn(int arg0) {
            Log.i("connection", "reconnectingIn");
        }
 
        @Override
        public void connectionClosedOnError(Exception arg0) {
            Log.i("connection", "connectionClosedOnError");
            
        }

实战案例如下:

android即时通讯技术基于XMPP协议asmack聊天功能实战

android即时通讯技术基于XMPP协议asmack聊天功能实战

android即时通讯技术基于XMPP协议asmack聊天功能实战

沟通联系qq2729404527  微信:code588