之前的开发,我并没有集成通讯类的SDK,所以这次就试试。我选择了环信IM,他提供了两种一种是快速EaseUi集成还有一个就是根据文档以及API去集成,个人感觉EaseUi已经挺不错了,我们稍微增加,删除或者替换替换基本可以满足大部分需求。我是作为一个开发者本着想多了解一点的想法就慢慢去集成了。
我很难去把我锁集成的每个细节以及问题有写出来,但是思路可以理理
1.集成所需要的依赖之类的东西
2.登录注册,自己测试Demo,就自己代码注册登录了
3.获取联系人以及联系人的增删改查,加黑等各种处理。这一块的处理的核心就是监听以及及时的刷新,下面是个人代码直接黏贴过来:
/** * 自己的联系人添加,删除 * 自己受到邀请 * 自己的请求被别人同意,拒绝 */ class MyContactListener implements EMContactListener { @Override public void onContactAdded(String s) { Log.e("TAG", "新增的好友:" + s); if (!ContactListManager.getInstance().containContact(s)) { ContactListManager.getInstance().saveContact(s); } localBroadcastManager.sendBroadcast(new Intent(Constact.ACTION_CONTACT_CHANAGED)); } @Override public void onContactDeleted(String s) { Log.e("TAG", "删除了的好友:" + s); if (ContactListManager.getInstance().containContact(s)) { ContactListManager.getInstance().deleteContact(s); } localBroadcastManager.sendBroadcast(new Intent(Constact.ACTION_CONTACT_CHANAGED)); } @Override public void onContactInvited(String userName, String s1) { Log.e("TAG", "收到的好友邀请:" + userName); //批量删除userName之前发过来的消息,用最新的取代 GreenDaoHelp.getInstance().getSession().getInviteMessageEnityDao().queryBuilder() .where(InviteMessageEnityDao.Properties.From.eq(userName)) .buildDelete().executeDeleteWithoutDetachingEntities(); // save invitation as message InviteMessageEnity msg = new InviteMessageEnity(); msg.setFrom(userName); msg.setTime(System.currentTimeMillis()); msg.setReason(s1); // set invitation status msg.setStatus(InviteMessageStatus.BEINVITEED); notifyNewInviteMessage(msg); localBroadcastManager.sendBroadcast(new Intent(Constact.ACTION_CONTACT_CHANAGED)); } @Override public void onFriendRequestAccepted(String userName) { Log.e("TAG", userName + "接受我的请求:"); GreenDaoHelp.getInstance().getSession().getInviteMessageEnityDao().queryBuilder() .where(InviteMessageEnityDao.Properties.From.eq(userName)).buildDelete().executeDeleteWithoutDetachingEntities(); InviteMessageEnity msg = new InviteMessageEnity(); msg.setFrom(userName); msg.setTime(System.currentTimeMillis()); // set invitation status msg.setStatus(InviteMessageStatus.BEAGREED); notifyNewInviteMessage(msg); localBroadcastManager.sendBroadcast(new Intent(Constact.ACTION_CONTACT_CHANAGED)); } @Override public void onFriendRequestDeclined(String userName) { MyToast.showToast(userName + " 拒绝了你的好友请求"); } }
我个人理解就是增,删,改,查等,所有的操作最终都会在这个中枢被监听,所以我只要在这个地方进行统一处理就不会出现漏处理导致的不刷新或者重复刷新导致的消耗性能。
4.消息发送,接收,也是有一个核心的监听,我也是以这个监听为中枢进行消息的刷新的,刷的是消息的Adapter里面的View(发送,接收,已读,失败.....):
EMMessageListener msgListener = new EMMessageListener() { @Override public void onMessageReceived(List<EMMessage> messages) { //收到消息 List<String> justRemoveList = getJustRemoveList(); for (int i = 0; i < messages.size(); i++) { EMMessage emMessage = messages.get(i); String from = emMessage.getFrom(); if (justRemoveList.size() > 0 && getJustRemoveList().contains(from)) { GreenDaoHelp.getInstance().getSession().getRemoveConverSationEnityDao().deleteByKey(from); } } localBroadcastManager.sendBroadcast(new Intent(Constact.ACTION_MESSAGE_CHANAGED)); Log.e("TAG", "收到消息"); } @Override public void onCmdMessageReceived(List<EMMessage> messages) { //收到透传消息 Log.e("TAG", "收到透传消息"); } @Override public void onMessageRead(List<EMMessage> messages) { //收到已读回执 localBroadcastManager.sendBroadcast(new Intent(Constact.ACTION_MESSAGE_CHANAGED)); Log.e("TAG", "收到已读回执"); } @Override public void onMessageDelivered(List<EMMessage> message) { //收到已送达回执 localBroadcastManager.sendBroadcast(new Intent(Constact.ACTION_MESSAGE_CHANAGED)); Log.e("TAG", "收到已送达回执"); } @Override public void onMessageRecalled(List<EMMessage> messages) { //消息被撤回 Log.e("TAG", "消息被撤回"); for (EMMessage msg : messages) { // if (msg.getChatType() == ChatType.GroupChat && EaseAtMessageHelper.get().isAtMeMsg(msg)) { // EaseAtMessageHelper.get().removeAtMeGroup(msg.getTo()); // } EMMessage msgNotification = EMMessage.createReceiveMessage(EMMessage.Type.TXT); EMTextMessageBody txtBody = new EMTextMessageBody(String.format(getCuurentActivity().getString(R.string.msg_recall_by_user), msg.getFrom())); msgNotification.addBody(txtBody); msgNotification.setFrom(msg.getFrom()); msgNotification.setTo(msg.getTo()); msgNotification.setUnread(false); msgNotification.setMsgTime(msg.getMsgTime()); msgNotification.setLocalTime(msg.getMsgTime()); msgNotification.setChatType(msg.getChatType()); msgNotification.setAttribute(MESSAGE_TYPE_RECALL, true); msgNotification.setStatus(EMMessage.Status.SUCCESS); EMClient.getInstance().chatManager().saveMessage(msgNotification); } localBroadcastManager.sendBroadcast(new Intent(Constact.ACTION_MESSAGE_CHANAGED)); } @Override public void onMessageChanged(EMMessage message, Object change) { //消息状态变动 Log.e("TAG", "消息状态变动"); localBroadcastManager.sendBroadcast(new Intent(Constact.ACTION_MESSAGE_CHANAGED)); } };
4.有监听也不行,得发消息。我使用的消息机制是广播,严格起来说是本地广播LocalBroadcastreceiver,单利,使用方便,方便控制注册和反注册,另外广播作为四大组件之一,可以跨进程
5.消息发送,接收的View展示,就是一个Recycler,其核心就是Adapter,他的核心就是分为各种消息类型的View,我是将View分为左右两个View的没有复用。这个没什么难度,唯一需要做好的就是其显示发送消息整个过程中不同类型的ViewHolder布局根据不同的消息状态来进行不同的展示(发送中,成功 失败 已读 未读等),就是麻烦点,可以参考Demo做 需要改的自己在改改没问题
6.点击笑脸,Emoji图,选择图片相机 文件 开语音 开视频这块功,这里我是参照Demo处理的但是略有不同,本质是一回事。只是需要注意的是,在这种逻辑比较多,功能也比较多的复杂业务,最好是做到像走方阵一样,整齐划一。就比如switch,case类似,由一个大的接口进行统一管理这些不同的点击事件,这样便于阅读和管理
总结:即时通讯,主要就是找到中枢监听,进行统一管理并通过广播发送给相关的界面进行状态更新,另外就是做到代码的规范,尤其是逻辑多,复杂,但有属于一大块的时候,通过接口一个一个清晰的导出去。最后就是数据缓存这一块,当然他也是为了提高性能,也是围绕中枢监听进行更新,插入等操作的。