有奖捉虫:云通信与企业服务文档专题,速来> HOT

展示会话列表

用户在登录 App 后,可以像微信那样展示最近会话列表。整个过程分为拉取会话列表处理更新通知更新 UI 内容(包括未读计数),本文主要介绍这些步骤的详细细节。

拉取会话列表

用户在登录后调用 getConversationList() 拉取本地会话列表做 UI 展示,会话列表是一个 V2TIMConversation 对象的列表,每一个对象都代表一个会话。

由于本地会话可能很多(例如超过500个),一次性全部加载完毕可能会耗时很久,导致界面展示比较慢。为了提升用户体验,getConversationList() 接口支持分页拉取能力:

  1. 首次调用 getConversationList() 接口时,可以指定其参数 nextSeq 为0 ,表示从头开始拉取会话列表,并指定 count 为50, 表示一次拉取50个会话对象。
  2. IM SDK 按照从新到旧的顺序拉取会话列表,当首次拉取会话列表成功后,getConversationList() 的回调结果 V2TIMConversationResult 中会包含下次分页拉取的 nextSeq 字段以及会话拉取是否完成的 isFinish 字段:
    • 如果 isFinished 返回 true,表示所有会话已经拉取完成。
    • 如果 isFinished 返回 false ,表示还有更多的会话可以拉取。此时并不意味着要立刻开始拉取“下一页”的会话列表。在常见的通信软件中,分页拉取通常由用户的滑动操作触发的,用户每下拉一次会话列表就触发一次分页拉取。
  3. 当用户继续下拉会话列表时,如果还有没有拉取下来的会话列表,可以继续调用 getConversationList 接口,并传入新一轮的 nextSeqcount 参数(数值来自上一次拉取返回的 V2TIMConversationResult 对象)。
  4. 重复执行 步骤3 直至 isFinished 返回 true

显示会话信息

获取到 V2TIMConversation 对象后,即可在 UI 上展示,V2TIMConversation 有如下关键字段常被用于构造会话列表:

字段名称 含义
getShowName () 会话名称:
  • 如果是单聊,此接口会优先返回对方好友备注,若没有备注或者不是好友,则返回对方昵称,若昵称也没有,则返回对方的 UserID。
  • 如果是群聊,会显示群的名称。
getFaceUrl () 会话头像:
  • 如果是单聊,会显示对方的头像。
  • 如果是群聊,会显示群头像。
getRecvOpt () 消息接收选项,一般用于群会话,可以显示该群是否设置了“消息免打扰”模式。
getUnreadCount () 用于显示未读计数,表示有多少条未读消息。
getLastMessage () 最后一条消息,用于显示会话的消息摘要。

更新会话列表

IM SDK 会在登录成功后、用户上线后、以及断线重连后,自动更新会话列表。更新过程如下:

  • 当有会话更新时,例如新收到一条消息,SDK 会通过 V2TIMConversationListener 中的 onConversationChanged 事件通知您。
  • 当有会话新增时,SDK 会通过 V2TIMConversationListener 中的 onNewConversation 事件通知您。
    注意:

    为保证会话列表顺序符合最后一条消息的排序原则,您需要根据 getLastMessage 中的 getTimestamp 对数据源重新排序。

示例代码

示例代码将介绍如何拉取、展示和更新会话列表:

// 1. 设置会话监听
V2TIMManager.getConversationManager().setConversationListener(this);
// 2. 先拉取50个本地会话做 UI 展示,nextSeq 第一次拉取传0
V2TIMManager.getConversationManager().getConversationList(0, 50, 
    new V2TIMValueCallback<V2TIMConversationResult>() {
    @Override
    public void onError(int code, String desc) {
        // 拉取会话列表失败
    }
    @Override
    public void onSuccess(V2TIMConversationResult v2TIMConversationResult) {
        // 拉取成功,更新 UI 会话列表
        updateConversation(v2TIMConversationResult.getConversationList(), false);
        if (!v2TIMConversationResult.isFinished()) {
            V2TIMManager.getConversationManager().getConversationList(
                v2TIMConversationResult.getNextSeq(), 50, 
                    new V2TIMValueCallback<V2TIMConversationResult>() {
            @Override
            public void onError(int code, String desc) {}
            @Override
            public void onSuccess(V2TIMConversationResult v2TIMConversationResult) {
                // 拉取成功,更新 UI 会话列表
                updateConversation(v2TIMConversationResult.getConversationList(), false);
            }
        });
    }
}
// 3.1 收到会话新增的回调
@Override
public void onNewConversation(List<V2TIMConversation> conversationList) {
    updateConversation(conversationList, true);
}
// 3.2 收到会话更新的回调
@Override
public void onConversationChanged(List<V2TIMConversation> conversationList) {
    updateConversation(conversationList, true);
}

private void updateConversation(List<V2TIMConversation> convList, boolean needSort) {
    for (int i = 0; i < convList.size(); i++) {
        V2TIMConversation conv = convList.get(i);
        boolean isExit = false;
        for (int j = 0; j < uiConvList.size(); j++) {
            V2TIMConversation uiConv = uiConvList.get(j);
            // UI 会话列表存在该会话,则替换
            if (uiConv.getConversationID().equals(conv.getConversationID())) {
                uiConvList.set(j, conv);
                isExit = true;
                break;
            }
        }
        // UI 会话列表没有该会话,则新增
        if (!isExit) {
            uiConvList.add(conv);
        }
    }
    // 4. 按照会话 lastMessage 的 timestamp 对 UI 会话列表做排序并更新界面
    if (needSort) {
        Collections.sort(uiConvList, new Comparator<V2TIMConversation>() {
            @Override
            public int compare(V2TIMConversation o1, V2TIMConversation o2) {
                if (o1.getLastMessage().getTimestamp() > o2.getLastMessage().getTimestamp()) {
                        return -1;
                } else {
                        return 1;
                }
            }
        });
    }
    ...
    mAdapter.setDataResource(uiConvList);
    mAdapter.notifyDataSetChanged();
}

获取所有未读消息总数

调用 getTotalUnreadMessageCount 接口可以获取所有会话的未读消息总数。您不用再遍历会话列表,把单个会话的未读数相加,才能得到未读总数。当会话的未读总数发生变更的时候,SDK 会主动向您的 App 回调 onTotalUnreadMessageCountChanged ,把最新的未读总数通知给您。

仅增强版 5.3.425 及以上版本支持。

置顶会话

会话置顶指的是把特定的好友或者群会话固定在会话列表的最前面,新版本 SDK 增加了主动设置或者取消会话置顶的接口 pinConversation ,同时支持漫游和多端同步。
会话对象 V2TIMConversation 新增了 isPinned 接口,用于判断会话的置顶状态。当会话的置顶状态发生变更的时候,SDK 会向您的 App 回调 onConversationChanged

仅增强版 5.3.425 及以上版本支持。

删除会话

调用 deleteConversation 接口可以删除某个会话,会话删除默认关闭多端同步,可在控制台开启多端同步,删除会话时默认删除本地和服务器历史消息,且无法恢复。

草稿箱

在发送消息时,可能会遇到消息尚未编辑完就要切换至其它聊天窗口的情况,这些未编辑完的消息可通过 setConversationDraft 接口保存,以便于回到聊天界面后调用 getDraftText 继续编辑内容。

注意:

  • 草稿仅支持文本内容。
  • 草稿仅在本地保存,不会存储到服务器,因此不能多端同步,程序卸载重装会失效。

常见问题

1. 最近会话列表的保存数量上限是多少?

本地存储的会话列表没有数量上限,云端存储的会话列表最大数量为100(旗舰版用户可在控制台配置最高为500)。
如果一个会话长时间没有信息变更,该会话在云端最多保存7天,如需放宽限制,请 联系我们

2. 为什么换了一个手机登录相同帐号后拉取的会话列表不一致?

本地存储的会话和云端存储的会话并不总是一致的,如果用户不主动调用 deleteConversation 接口删除本地的会话,该会话就会一直存在。而云端存储的会话最大只会保存100条,且对于长时间没有信息变更的会话,云端最多保存7天,所以不同的终端本地显示的会话可能会不一样。

3. 为什么会拉取到重复的会话?

调用 getConversationList 接口拉取的会话可能已经通过 onNewConversation 回调接口添加到了 UI 会话列表的数据源中,因此为了避免重复添加同一个会话,您需要在 UI 会话列表数据源中根据 getConversationID 找到相同的会话并做替换。

4. IM SDK 支持会话置顶吗?

IM SDK 从5.3.425版本开始支持会话置顶功能并可以同步到云端。