工作篇 之 简单聊下有关环信的 “坑” ... [复制链接]

2019-2-2 12:02
静心Study 阅读:651 评论:0 赞:0
Tag:  

LZ-Says:相遇,相知,相恋,争执,平淡,压抑,愤懑,该画上句号了。

图片描述

前言

环信,Enmmm,牛逼,懵 ing ~!

最近这段时间一直围绕环信,在使用的过程中,遇到很多很多问题,自己都感觉蒙圈,烦躁。

还好,明远小哥哥很 nice,点拨给力,到位,赞一个~!

明天要开启新的征程了,希望一切顺利,加油哦~!

今天简单整理下,LZ 所经历到的环信之 “坑” ~~~

Enmmm,环信,你好

首先,列举本文将要描述的内容简述:

  • 查询本地消息历史记录

  • 清空聊天记录保留会话

  • 显示 “输入中。。。”

接着,我们进行逐步说明。

一、查询本地消息历史记录

搜索 API 文档,得出环信官方提供了如下不同类型接口:

在这里插入图片描述

经过文哥指点,最终确定使用如下类型接口:

在这里插入图片描述

原想着很美好,很 easy,分分钟,嗯,开始的代码如下:

List<EMMessage> resultList = mConversation.searchMsgFromDB(
        mSearchView.getText().toString(),
        System.currentTimeMillis(),
        50,
        null,
        EMConversation.EMSearchDirection.UP);
。。。
Adapter 更新即可

But,美滋滋的测试的时候,突然发现一个问题,只能搜索 汉字,输入 单个数字 或者 单个字母,则检索出所有数据。 百思不得其解,内心无数的 MMP,无奈下只能提交工单,嗯,工单好。

为环信敬业赞一个,But,回复的是,我们这边没事。

想问问有什么原因导致,嗯,你自己检查下。

咋检查啊,之前好好地,我就是在这个基础加了一个查询本地消息,怎么破?

文档也看了,度娘也扒光了,无招。项目又比较急,怎么办?

找出共性,逐步解决~!

List<EMMessage> resultList = mConversation.searchMsgFromDB(
        mSearchView.getText().toString(),
        System.currentTimeMillis(),
        50,
        null,
        EMConversation.EMSearchDirection.UP);
// 1. 创建临时存储 List
List<EMMessage> tempList = new ArrayList<>();
mMessageIDList = new ArrayList<>();
// 2. 循环遍历 进行手动过滤
for (int i = 0; i < resultList.size(); i++) {
    if (resultList.get(i).getBody() instanceof EMTextMessageBody) {
        if (((EMTextMessageBody) resultList.get(i).getBody()).getMessage().contains(mSearchView.getText().toString())) {
            tempList.add(resultList.get(i));
        }
    }
}
// 3. 将最后过滤后的 List 赋值到 RecyclerView 中的 List 并进行 notify 即可
if (mMessageList == null) {
    mMessageList = tempList;
} else {
    mMessageList.clear();
    mMessageList.addAll(tempList);
}

LZ 实属无奈,如有其他小伙伴也曾经遇到过,并完美解决,还望告知~

二、清空聊天记录保留会话

这个,真的比较坑了。

需求就是和小题目一样,聊天记录清空且会话不能删除。

好,那我们开始逐步解决这个问题,官网显示,清除聊天记录需要调用如下 API:

// 删除和某个user会话,如果需要保留聊天记录,传false
EMClient.getInstance().chatManager().deleteConversation(username, true);
// 删除当前会话的某条聊天记录
EMConversation conversation = EMClient.getInstance().chatManager().getConversation(username);
conversation.removeMessage(deleteMsg.msgId);

二话不说,拷贝进来再说。测试后,发现会话也被移除了,咋整,度娘呗。

经过了度娘以及工单后,发现了如下方法:

/**
 * clear the conversation history
 */
protected void emptyHistory() {
    String msg = getResources().getString(R.string.Whether_to_empty_all_chats);
    new EaseAlertDialog(getActivity(), null, msg, null, new EaseAlertDialog.AlertDialogUser() {

        @Override
        public void onResult(boolean confirmed, Bundle bundle) {
            if (confirmed) {
                if (conversation != null) {
                    conversation.clearAllMessages();
                }
                messageList.refresh();
                haveMoreData = true;
            }
        }
    }, true).show();
}

看似很美好,But,EaseUI 中对此进行了拦截,不信?截图为证:

在这里插入图片描述

Enmmm,嗨皮不?人给你拦截了,哇咔咔。

有的小伙伴说,你把这个干掉不就好了嘛?

嘿嘿嘿,彩蛋还是要自己去发掘的。

这里还是感谢明远老哥指点,模仿类似群加人,群删人发送时,本地插入消息。

So,开始模仿之路,说白了,我们要为我们的 EaseChatRow 新添加另外一种类型。

Step 1:为 EaseChatRow 新增一种类型

public static final String MESSAGE_PLACEHOLDER = "placeholder";

Step 2:创建 EaseChatRow 布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

Step 3:创建 EaseChatRow 实例类

public class EaseChatRowPlaceHolder extends EaseChatRow {

    public EaseChatRowPlaceHolder(Context context, EMMessage message, int position, BaseAdapter adapter) {
        super(context, message, position, adapter);
    }

    @Override
    protected void onInflateView() {
        inflater.inflate(R.layout.ease_row_place_holder, this);
    }

    @Override
    protected void onFindViewById() {
    }

    @Override
    protected void onViewUpdate(EMMessage msg) {
    }

    @Override
    protected void onSetUpView() {
    }

}

Step 4:来,搞个 P

public class EaseChatPlaceHolderPresenter extends EaseChatRowPresenter {

    @Override
    protected EaseChatRow onCreateChatRow(Context cxt, EMMessage message, int position, BaseAdapter adapter) {
        return new EaseChatRowPlaceHolder(cxt, message, position, adapter);
    }

    @Override
    public void onBubbleClick(EMMessage message) {
        super.onBubbleClick(message);
    }

    @Override
    protected void handleReceiveMessage(EMMessage message) {
        if (!message.isAcked() && message.getChatType() == EMMessage.ChatType.Chat) {
            try {
                EMClient.getInstance().chatManager().ackMessageRead(message.getFrom(), message.getMsgId());
            } catch (HyphenateException e) {
                e.printStackTrace();
            }
            return;
        }
        EaseDingMessageHelper.get().sendAckMessage(message);
    }
}

完成了以上几步,接下来,则是要为 EaseChatRow 指明我们定义的消息体类型即可。

Step 5:Adapter 针对特定的类型返回特定的 EaseChatRow

EaseMessageAdapter --> getItemViewType:

// 清除聊天消息 发送空字符
if (message.getBooleanAttribute(EaseConstant.MESSAGE_PLACEHOLDER, false)) {
    return message.direct() == EMMessage.Direct.RECEIVE ? MessageAdapterConstant.MESSAGE_TYPE_SENT_PLACE_HOLDER : MessageAdapterConstant.MESSAGE_TYPE_SENT_PLACE_HOLDER;
}

EaseMessageAdapter --> createChatRowPresenter:

else if (message.getBooleanAttribute(EaseConstant.MESSAGE_PLACEHOLDER, false)) {
     presenter = new EaseChatPlaceHolderPresenter();
} 

Step 6:最后,发送一条我们指定类型的消息

EMClient.getInstance().chatManager().deleteConversation(group.getId(), true);
EMClient.getInstance().chatManager().getConversation(group.getId(), EMConversation.EMConversationType.GroupChat, true);
// 记得,这边要创建一条发送消息,不然列表会出现小彩蛋 感谢我老哥
EMMessage message = EMMessage.createSendMessage(EMMessage.Type.TXT);
message.setChatType(EMMessage.ChatType.GroupChat);
EMTextMessageBody body = new EMTextMessageBody("");
message.setTo(group.getId());
message.addBody(body);
// 设置当前消息类型
message.setAttribute(MESSAGE_PLACEHOLDER, true);
message.setAttribute("hxId", SPUtils.get(AppConstant.HXID, "").toString());
message.setAttribute("avatar", SPUtils.get(AppConstant.AVATAR, "").toString());
message.setAttribute("groupId", group.getId() != null ? group.getId() : "");
message.setAttribute("cover", group.getCover() != null ? group.getCover() : "");
message.setUnread(false);
EMConversation conversation = EMClient.getInstance().chatManager().getConversation(group.getId());
conversation.appendMessage(message);

三、显示 “输入中。。。”

首先,我们先了解下有关输入状态官网简述:

监听用户 A 输入状态,一旦有文字输入,就每隔几秒通过透传消息将输入状态发送到聊天接受方 B,B 客户端收到输入状态透传后,提示用户 A 正在输入。

    • 用户 A 向用户B 发一条表示输入状态透传消息;

    • 用户 B 在收到消息后,判断当前是否在与 A 聊天的页面,如果在,显示 A 的输入状态;

    • 当隔几秒后没有再次收到 A 的输入状态,自动取消显示。

    注:“透传消息”是一种特殊类型的消息,收发双方不会存数据库,同时用户离线时也不会有推送,比较适合配合业务来处理一些功能。 并且 A 用户不需要不停的向 B 发送消息,可以设置一个时间,判断发送间隔。

    So,我们这个代码很 Easy。

    Step 1:编写我们发送透传消息体

    /**
     * 自定义时间间隔发送状态消息(单位:ms)
     */
    public int time = 2000;
    
    /**
     * 文本框第一次输入内容变化的时间
     */
    public long firstTime = System.currentTimeMillis();
    
    /**
     * 发送输入状态的透传消息
     */
    private void sendInputMsg(String inputState) {
        // 这里需要判断
        if (chatType == EaseConstant.CHATTYPE_SINGLE) {
            EMMessage cmdMsg = EMMessage.createSendMessage(EMMessage.Type.CMD);
            // 如果是群聊,需要设置 chattype,默认是单聊
            String action;
            if ("input".equals(inputState)) {
                action = "input";
            } else {
                action = "stopInput";
            }
            EMCmdMessageBody cmdBody = new EMCmdMessageBody(action);
            // 设置消息body
            cmdMsg.addBody(cmdBody);
            // 设置要发给谁,用户username 或者群聊groupid
            cmdMsg.setTo(toChatUsername);
            EMClient.getInstance().chatManager().sendMessage(cmdMsg);
        }
    }

    Step 2:EaseChatMenu 添加监听

    这里需要注意,什么时候发送 input,什么时候发送 inputStop。

    if (TextUtils.isEmpty(s)) {
        // 发送 inputStop 状态
        listener.onInputStatusListener("inputStop");
    } else {
        // 发送 input 状态
        listener.onInputStatusListener("input");
    }

    Step 3:实现监听

     @Override
     public void onInputStatusListener(String inputStatus) {
         if ("input".equals(inputStatus)) {
             if (System.currentTimeMillis() - firstTime > time) {
                 sendInputMsg("input");
                 firstTime = System.currentTimeMillis();
             }
         } else {
             sendInputMsg("inputStop");
         }
     }

    结束

    目前而言,LZ 经历的以上问题总结完成,如有遗漏,请指明,谢谢~

    剩下的以后遇到再补充吧~

    个人公众号

    不定期发布博文,最近有点忙,感谢老铁理解,欢迎关注~

    图片描述

    参考资料

    1. Android SDK API Doc:http://docs-im.easemob.com/im/android/sdk/apidoc

    2. 删除会话及聊天记录:http://docs-im.easemob.com/im/android/basics/message#%E5%88%A0%E9%99%A4%E4%BC%9A%E8%AF%9D%E5%8F%8A%E8%81%8A%E5%A4%A9%E8%AE%B0%E5%BD%95

    3. 输入状态提示:http://docs-im.easemob.com/im/other/integrationcases/inputstatus#%E8%BE%93%E5%85%A5%E7%8A%B6%E6%80%81%E6%8F%90%E7%A4%BA


    我来说两句
    您需要登录后才可以评论 登录 | 立即注册
    facelist
    所有评论(0)
    领先的中文移动开发者社区
    18620764416
    7*24全天服务
    意见反馈:1294855032@qq.com

    扫一扫关注我们

    Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粤ICP备15117877号 )