步骤4:好友列表以及状态(Roster and Presence)。
Roster:好友列表,但它不是一个表,而是一个比较复杂的类。
Presence:好友的状态,是Roster中包含的类,但有特殊作用。
大家阅读源码,了解Roster 与 Presence包含的信息。特别注意几个枚举类的不同,不要混淆了。
·加载列表:
通过Roster类的getInstanceFor()函数和connection就可以获得实例。通过getEntries就可以获得所有Entry,即是获得好友列表信息。
通过getPresence()函数可以获得Presence。
·监听列表:
通过addRosterListener()添加监听器,则可以监听好友的信息的变化,如上线下线等。
Roster参考代码:
roster = Roster.getInstanceFor(connection); roster.setSubscriptionMode(Roster.SubscriptionMode.manual); roster.addRosterListener(new RosterListener() { @Override public void entriesAdded(Collection<String> addresses) { for(String jid : addresses){ RosterEntry entry= roster.getEntry(jid); entries.put(jid,entry); } rosterChangedListener.rosterChanged(); } @Override public void entriesUpdated(Collection<String> addresses) { rosterChangedListener.rosterChanged(); } @Override public void entriesDeleted(Collection<String> addresses) { for(String jid : addresses){ entries.remove(jid); rosterChangedListener.rosterChanged(); } } @Override public void presenceChanged(Presence presence) { presenceHashMap.put(presence.getFrom(),presence); rosterChangedListener.rosterChanged(); } });
!注意!
当你直接写了代码并运行后,可能会发现Roster的Entries会是空的!这个问题笔者网上找了许久,最后发现是由于客户端运行过快,在登录后马上获取Roster,导致Roster内容为空,或则说在服务器还没有把Roster传过来时,代码已经运行完毕了。解决方法是在登录后将线程暂停一下,再获取一次Roster。
步骤5:多人聊天
多人聊天与单人聊天不同,其是基于XEP协议的,区别之处在于多人聊天要在服务器上创建聊天室,然后其他加入聊天室中聊天,而单人聊天则只是两个节点之间的对话。其实对于这里的设计有点不太理解,因为这样使用两套设计令到实现客户端时需要进行两套实现,然而这两种聊天方式是有很多共性的,因而会导致很多的重复。我看了看微信的实现方式,微信应该是将两种聊天方式统一起来的,单人聊天中可以随时添加其他人,也就是说只使用了XMPP中多人聊天方式这一种实现。
多人聊天中重要的类有:
MultiUserChat:类似单人聊天的Chat,是多人聊天会话类。
MultiUserChatManager:多人聊天会话的管理类。
接口:
MessageListener:消息监听接口
多人聊天比单人聊天的创建复杂一些,多了创建、发送邀请、加入聊天室三个步骤。
参考代码:
加入聊天室
public void joinChattingRoom(MultiUserChat multiUserChat,String nickname) throws SmackException.NotConnectedException, XMPPException.XMPPErrorException, SmackException.NoResponseException { multiUserChat.join(nickname); dataManager.addToChatsList(multiUserChat.getRoom()); chatsMap.put(multiUserChat.getRoom(), multiUserChat); multiUserChat.addMessageListener(new MessageListener() { @Override public void processMessage(Message message) { if(message.getType().equals(Message.Type.groupchat)){ dataManager.processMessage(message); } } }); }
邀请监听
multiUserChatManager.addInvitationListener(new InvitationListener() { @Override public void invitationReceived(XMPPConnection xmppConnection, MultiUserChat multiUserChat, String inviter, String reason, String s3, Message message) { //回调一下activity,弹框 invitationReceivedListener.onInvitationReceived(multiUserChat, inviter , reason); } });
创建聊天室
public void createMultiUserChat(String roomName,String nickname) throws XMPPException.XMPPErrorException, SmackException { String jid = roomName+"@conference.192.168.0.101"; MultiUserChat muc = multiUserChatManager.getMultiUserChat(jid); muc.create(nickname); dataManager.addToChatsList(jid); chatsMap.put(jid, muc); muc.sendConfigurationForm(new Form(DataForm.Type.submit)); muc.addMessageListener(new MessageListener() { @Override public void processMessage(Message message) { if (message.getType().equals(Message.Type.groupchat)) { dataManager.processMessage(message); } } }); }
以上就是实现XMPP聊天客户端的核心内容,其他额外的实现就多说,毕竟本人较菜,处于学习中,不值得参考。
项目小结:
基本上只是简单地实现了一个文本通信的简单程序,收获也颇多。
首先,学会了基于开源的库怎么去开发,流程大概是:
读理论——>读库的开发文档(边度边动手)——>读源码——>设计模块——>实现设计。
第二,当程序写着写着,发现数据异常乱,原因是没有将数据剥离出来,后来准备写一个数据层,写了一些,发现数据层不好写,原因是数据类型有多种,以及某些类的耦合性导致数据剥离会重复做工,例如Roster类,包含了数据。后来大致看了一下Spark的设计,发现它不是分出数据层,而是将每一种数据设计一个容器,感觉这个思路比集中一个数据层要好一点。
第三,在架构方面比以前小有长进,对比了Spark的架构,发现设计的思路较为类似,都是UI分一层,利用管理类作为控制。
第四,当然就是熟悉了部分网络编程的知识了,了解了一些协议之间的区别。