即时通信 IM Android&iOS&Windows&Mac(会话列表)

用户在登录 App 后,可以像微信或 QQ 那样展示最近会话列表,方便找到目标会话。会话列表如下图所示会话列表功能主要分为获取会话列表、处理会话列表更新。这里说明具体的实现细节。

相关产品
即时通信 IM 产品页,含版本规格、价格与购买入口。

一、获取会话列表基础接口

你可以调用 getConversationList(Java / Swift / Objective-C / C++) 获取会话列表。该接口拉取的是本地缓存的会话,如果服务器会话有更新,SDK 内部会自动同步,然后在 V2TIMConversationListener 回调告知客户。

用户的会话以列表的形式返回,列表中存储的是 V2TIMConversation 对象。目前 IM SDK 对会话列表的排序规则为:

·5.5.892 及以后版本, 获取的会话列表默认已经按照会话对象的 orderKey 做了排序。orderKey 值越大,代表该会话排序越靠前。orderKey 字段是整型数,当发送新消息、接收新消息、设置草稿或置顶会话时,会话被激活,orderKey 字段会增大。

·5.5.892 以前版本,获取的会话列表默认已经按照会话 lastMessage -> timestamp 做了排序。timestamp 越大,会话越靠前。

注意:在某些场景下,可能出现会话的 lastMessage 为空(例如清空会话消息)。如果你使用 5.5.892 以前的 SDK,使用 lastMessage 排序时需要额外处理这种异常。我们建议你升级到 5.5.892 及以后的版本,使用 orderKey 字段排序。

你可以使用 getConversationList 实现一次性拉取或分页拉取。参考下文说明。

二、一次性拉取

一次性拉取适合会话数量比较少的情况(100 个以内)。此时可以将拉取的 count 设置为 INT_MAX(一般会话数量不会达到 INT_MAX 这么多)。

示例代码如下:

JavaSwiftObjective-CC++V2TIMManager.getConversationManager().getConversationList(0, Integer.MAX_VALUE, new V2TIMValueCallback<V2TIMConversationResult>() { @Override public void onSuccess(V2TIMConversationResult v2TIMConversationResult) { long nextSeq = v2TIMConversationResult.getNextSeq(); Log.i("imsdk", "success nextSeq:" + nextSeq + ", isFinish:" + v2TIMConversationResult.isFinished()); List<V2TIMConversation> v2TIMConversationList = v2TIMConversationResult.getConversationList(); for (V2TIMConversation v2TIMConversation : v2TIMConversationList) { Log.i("imsdk", "success showName:" + v2TIMConversation.getShowName()); } } @Override public void onError(int code, String desc) { Log.i("imsdk", "failure, code:" + code + ", desc:" + desc); }});V2TIMManager.shared.getConversationList(nextSeq: 0, count: Int32.max) { list, nextSeq, isFinished in list.forEach { item in print(item.description) }} fail: { code, desc in print("getConversationList fail, \\(code), \\(desc)")}[[V2TIMManager sharedInstance] getConversationList:0 count:INT_MAX succ:^(NSArray<V2TIMConversation *> *list, uint64_t lastTS, BOOL isFinished) { // 获取成功,list 为会话列表} fail:^(int code, NSString *msg) { // 获取失败}];template <class T>class ValueCallback final : public V2TIMValueCallback<T> {public: using SuccessCallback = std::function<void(const T&)>; using ErrorCallback = std::function<void(int, const V2TIMString&)>; ValueCallback() = default; ~ValueCallback() override = default; void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) { success_callback_ = std::move(success_callback); error_callback_ = std::move(error_callback); } void OnSuccess(const T& value) override { if (success_callback_) { success_callback_(value); } } void OnError(int error_code, const V2TIMString& error_message) override { if (error_callback_) { error_callback_(error_code, error_message); } }private: SuccessCallback success_callback_; ErrorCallback error_callback_;};uint64_t nextSeq = 0;uint32_t count = std::numeric_limits<uint32_t>::max();auto callback = new ValueCallback<V2TIMConversationResult>{};callback->SetCallback( [=](const V2TIMConversationResult& conversationResult) { // 获取会话列表成功 delete callback; }, [=](int error_code, const V2TIMString& error_message) { // 获取会话列表失败 delete callback; });V2TIMManager::GetInstance()->GetConversationManager()->GetConversationList(nextSeq, count, callback);

三、分页拉取

如果你的应用场景会产生较多的会话数,考虑到加载效率、网络省流,我们建议你采用分页拉取的方式。每次分页拉取的数量建议不超过 100 个。

分页拉取的步骤:

1. 首次调用 getConversationList 时,指定参数 nextSeq 为 0(表示从头开始拉取会话列表),指定 count 为 50(表示一次拉取 50 个会话对象)。

2. 首次拉取会话列表成功后,getConversationList 的回调结果 V2TIMConversationResult 中会包含 nextSeq(下次分页拉取的字段)、isFinish(会话拉取是否完成)。

·如果 isFinished 为 true,表示所有会话已经拉取完成。

·如果 isFinished 为 false,表示还有更多的会话可以拉取。此时并不意味着要立刻开始拉取 “下一页” 的会话列表。在常见的软件中,分页拉取通常由用户的滑动操作触发的,用户每上拉一次会话列表就触发一次分页拉取。

3. 当用户继续上拉会话列表时,如果还有更多的会话可以拉取,可以继续调用 getConversationList 接口,并传入新一轮的 nextSeq(数值来自上一次拉取返回的 V2TIMConversationResult 对象)和 count 参数。

4. 重复执行【步骤 3】直至 isFinished 返回 true。

示例代码如下:

JavaSwiftObjective-CC++V2TIMManager.getConversationManager().getConversationList(0, 20, new V2TIMValueCallback<V2TIMConversationResult>() { @Override public void onSuccess(V2TIMConversationResult v2TIMConversationResult) { long nextSeq = v2TIMConversationResult.getNextSeq(); Log.i("imsdk", "success nextSeq:" + nextSeq + ", isFinish:" + v2TIMConversationResult.isFinished()); List<V2TIMConversation> v2TIMConversationList = v2TIMConversationResult.getConversationList(); for (V2TIMConversation v2TIMConversation : v2TIMConversationList) { Log.i("imsdk", "success showName:" + v2TIMConversation.getShowName()); } if (!v2TIMConversationResult.isFinished()) { getConversationListInternal(nextSeq, 20); } } @Override public void onError(int code, String desc) { Log.i("imsdk", "failure, code:" + code + ", desc:" + desc); }});var isFinished: Bool = falsevar nextSeq: UInt64 = 0// 用户上拉会话列表到底部,没有更多会话数据展示时触发func loadConversation() { if self.isFinished { return } weak var weakSelf = self V2TIMManager.shared.getConversationList(nextSeq: UInt(self.nextSeq), count: 20, succ: { (list, nextSeq, isFinished) in // 拉取成功 guard let strongSelf = weakSelf else { return } // 更新下一次拉取的锚点 nextSeq 和是否完成拉取标识位 isFinished strongSelf.nextSeq = UInt64(nextSeq) strongSelf.isFinished = isFinished // 用 list 更新 UI }, fail: { (code, msg) in // 拉取失败,结束本次拉取 self.isFinished = true })}// 用户上拉会话列表到底部,没有更多会话数据展示时触发- (void)loadConversation { if (self.isFinished) { return; } @weakify(self) [[V2TIMManager sharedInstance] getConversationList:self.nextSeq count:20 // 每次拉 20 个会话 succ:^(NSArray<V2TIMConversation *> *list, uint64_t nextSeq, BOOL isFinished) { // 拉取成功 @strongify(self) // 更新下一次拉取的锚点 nextSeq 和是否完成拉取标识位 isFinished self.nextSeq = nextSeq; self.isFinished = isFinished; // 用 list 更新 UI } fail:^(int code, NSString *msg) { // 拉取失败,结束本次拉取 self.isFinished = YES; }];}template <class T>class ValueCallback final : public V2TIMValueCallback<T> {public: using SuccessCallback = std::function<void(const T&)>; using ErrorCallback = std::function<void(int, const V2TIMString&)>; ValueCallback() = default; ~ValueCallback() override = default; void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) { success_callback_ = std::move(success_callback); error_callback_ = std::move(error_callback); } void OnSuccess(const T& value) override { if (success_callback_) { success_callback_(value); } } void OnError(int error_code, const V2TIMString& error_message) override { if (error_callback_) { error_callback_(error_code, error_message); } }private: SuccessCallback success_callback_; ErrorCallback error_callback_;};uint64_t nextSeq = 0;uint32_t count = 20;auto callback = new ValueCallback<V2TIMConversationResult>{};callback->SetCallback( [=](const V2TIMConversationResult& conversationResult) { // 获取会话列表成功 if (!conversationResult.isFinished) { nextSeq = conversationResult.nextSeq; // 继续获取 … } delete callback; }, [=](int error_code, const V2TIMString& error_message) { // 获取会话列表失败 delete callback; });V2TIMManager::GetInstance()->GetConversationManager()->GetConversationList(nextSeq, count, callback);

四、获取会话列表高级接口

如果以上的普通接口无法满足你对拉取会话列表的需求,我们还提供了高级接口 getConversationListByFilter (Java / Swift / Objective-C / C++),其中拉取会话的 V2TIMConversationListFilter 详解如下:

属性 含义 说明
type 会话类型(填 0 代表不过滤此项) C2C 或者群组会话
conversationGroup 会话分组名称(不填写代表不过滤此项) 不是群组名称,是会话分组的名称,详情请参见 会话分组
markType 会话标记类型(填 0 代表不过滤此项) 详情请参见 会话标记
hasUnreadCount 会话包含未读数 true :返回包含未读数的会话;false:返回所有会话
hasGroupAtInfo 会话包含群 @ 消息 true :返回包含群 @ 消息的会话;false:返回所有会话

五、拉取单聊或群聊会话

JavaSwiftObjective-CC++V2TIMConversationListFilter filter = new V2TIMConversationListFilter();filter.setConversationType(V2TIMConversation.V2TIM_C2C); //拉取单聊会话// filter.setConversationType(V2TIMConversation.V2TIM_GROUP); //拉取群聊会话V2TIMManager.getConversationManager().getConversationListByFilter(filter, 0, 50, new V2TIMValueCallback<V2TIMConversationResult>() { @Override public void onSuccess(V2TIMConversationResult v2TIMConversationResult) { // 获取会话列表成功 } @Override public void onError(int code, String desc) { // 获取会话列表失败 }});let filter = V2TIMConversationListFilter()filter.type = .V2TIM_C2C // 拉取单聊会话// filter.type = .V2TIM_GROUP // 拉取群聊会话V2TIMManager.shared.getConversationListByFilter(filter: filter, nextSeq: 0, count: 50, succ: { (list, nextSeq, isFinished) in // 获取会话列表成功,list 为会话列表}, fail: { (code, desc) in // 获取会话列表失败})V2TIMConversationListFilter *filter = [[V2TIMConversationListFilter alloc] init];filter.type = V2TIM_C2C; //拉取单聊会话// filter.type = V2TIM_GROUP; //拉取群聊会话[[V2TIMManager sharedInstance] getConversationListByFilter:filter nextSeq:0 count:50 succ:^(NSArray<V2TIMConversation *> *list, uint64_t nextSeq, BOOL isFinished) { // 获取会话列表成功,list 为会话列表} fail:^(int code, NSString *desc) { // 获取会话列表失败}];template <class T>class ValueCallback final : public V2TIMValueCallback<T> {public: using SuccessCallback = std::function<void(const T&)>; using ErrorCallback = std::function<void(int, const V2TIMString&)>; ValueCallback() = default; ~ValueCallback() override = default; void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) { success_callback_ = std::move(success_callback); error_callback_ = std::move(error_callback); } void OnSuccess(const T& value) override { if (success_callback_) { success_callback_(value); } } void OnError(int error_code, const V2TIMString& error_message) override { if (error_callback_) { error_callback_(error_code, error_message); } }private: SuccessCallback success_callback_; ErrorCallback error_callback_;};V2TIMConversationListFilter filter;filter.type = V2TIMConversationType::V2TIM_C2C; // 拉取单聊会话// filter.type = V2TIMConversationType::V2TIM_GROUP; //拉取群聊会话auto callback = new ValueCallback<V2TIMConversationResult>{};callback->SetCallback( [=](const V2TIMConversationResult& conversationResult) { // 获取会话列表成功 delete callback; }, [=](int error_code, const V2TIMString& error_message) { // 获取会话列表失败 delete callback; });V2TIMManager::GetInstance()->GetConversationManager()->GetConversationListByFilter(filter, 0, 50, callback);

六、拉取指定分组会话

JavaSwiftObjective-CC++V2TIMConversationListFilter filter = new V2TIMConversationListFilter();filter.setConversationGroup("conversation_group");V2TIMManager.getConversationManager().getConversationListByFilter(filter, 0, 50, new V2TIMValueCallback<V2TIMConversationResult>() { @Override public void onSuccess(V2TIMConversationResult v2TIMConversationResult) { // 获取会话列表成功 } @Override public void onError(int code, String desc) { // 获取会话列表失败 }});let filter = V2TIMConversationListFilter()filter.conversationGroup = "conversation_group"V2TIMManager.shared.getConversationListByFilter(filter: filter, nextSeq: 0, count: 10) { list, nextSeq, isFinished in list.forEach { item in print(item.description) }} fail: { code, desc in print("getConversationList fail, \\(code), \\(desc)")}V2TIMConversationListFilter *filter = [[V2TIMConversationListFilter alloc] init];filter.conversationGroup = @"conversation_group";[[V2TIMManager sharedInstance] getConversationListByFilter:filter nextSeq:0 count:50 succ:^(NSArray<V2TIMConversation *> *list, uint64_t nextSeq, BOOL isFinished) { // 获取会话列表成功,list 为会话列表} fail:^(int code, NSString *desc) { // 获取会话列表失败}];template <class T>class ValueCallback final : public V2TIMValueCallback<T> {public: using SuccessCallback = std::function<void(const T&)>; using ErrorCallback = std::function<void(int, const V2TIMString&)>; ValueCallback() = default; ~ValueCallback() override = default; void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) { success_callback_ = std::move(success_callback); error_callback_ = std::move(error_callback); } void OnSuccess(const T& value) override { if (success_callback_) { success_callback_(value); } } void OnError(int error_code, const V2TIMString& error_message) override { if (error_callback_) { error_callback_(error_code, error_message); } }private: SuccessCallback success_callback_; ErrorCallback error_callback_;};V2TIMConversationListFilter filter;filter.conversationGroup = u8"conversation_group";auto callback = new ValueCallback<V2TIMConversationResult>{};callback->SetCallback( [=](const V2TIMConversationResult& conversationResult) { // 获取会话列表成功 delete callback; }, [=](int error_code, const V2TIMString& error_message) { // 获取会话列表失败 delete callback; });V2TIMManager::GetInstance()->GetConversationManager()->GetConversationListByFilter(filter, 0, 50, callback);

七、拉取指定标记会话

JavaSwiftObjective-CC++V2TIMConversationListFilter filter = new V2TIMConversationListFilter();filter.setMarkType(V2TIMConversation.V2TIM_CONVERSATION_MARK_TYPE_STAR);V2TIMManager.getConversationManager().getConversationListByFilter(filter, 0, 50, new V2TIMValueCallback<V2TIMConversationResult>() { @Override public void onSuccess(V2TIMConversationResult v2TIMConversationResult) { // 获取会话列表成功 } @Override public void onError(int code, String desc) { // 获取会话列表失败 }});let filter = V2TIMConversationListFilter()filter.markType = .V2TIM_CONVERSATION_MARK_TYPE_STAR;V2TIMManager.shared.getConversationListByFilter(filter: filter, nextSeq: 0, count: 10) { list, nextSeq, isFinished in list.forEach { item in print(item.description) }} fail: { code, desc in print("getConversationList fail, \\(code), \\(desc)")}V2TIMConversationListFilter *filter = [[V2TIMConversationListFilter alloc] init];filter.markType = V2TIM_CONVERSATION_MARK_TYPE_STAR;[[V2TIMManager sharedInstance] getConversationListByFilter:filter nextSeq:0 count:50 succ:^(NSArray<V2TIMConversation *> *list, uint64_t nextSeq, BOOL isFinished) { // 获取会话列表成功,list 为会话列表} fail:^(int code, NSString *desc) { // 获取会话列表失败}];template <class T>class ValueCallback final : public V2TIMValueCallback<T> {public: using SuccessCallback = std::function<void(const T&)>; using ErrorCallback = std::function<void(int, const V2TIMString&)>; ValueCallback() = default; ~ValueCallback() override = default; void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) { success_callback_ = std::move(success_callback); error_callback_ = std::move(error_callback); } void OnSuccess(const T& value) override { if (success_callback_) { success_callback_(value); } } void OnError(int error_code, const V2TIMString& error_message) override { if (error_callback_) { error_callback_(error_code, error_message); } }private: SuccessCallback success_callback_; ErrorCallback error_callback_;};V2TIMConversationListFilter filter;filter.markType = V2TIMConversationMarkType::V2TIM_CONVERSATION_MARK_TYPE_STAR;auto callback = new ValueCallback<V2TIMConversationResult>{};callback->SetCallback( [=](const V2TIMConversationResult& conversationResult) { // 获取会话列表成功 delete callback; }, [=](int error_code, const V2TIMString& error_message) { // 获取会话列表失败 delete callback; });V2TIMManager::GetInstance()->GetConversationManager()->GetConversationListByFilter(filter, 0, 50, callback);

八、拉取含有未读数的会话

JavaSwiftObjective-CC++V2TIMConversationListFilter filter = new V2TIMConversationListFilter();filter.setHasUnreadCount(true);V2TIMManager.getConversationManager().getConversationListByFilter(filter, 0, 50, new V2TIMValueCallback<V2TIMConversationResult>() { @Override public void onSuccess(V2TIMConversationResult v2TIMConversationResult) { // 获取会话列表成功 } @Override public void onError(int code, String desc) { // 获取会话列表失败 }});let filter = V2TIMConversationListFilter()filter.hasUnreadCount = true;V2TIMManager.shared.getConversationListByFilter(filter: filter, nextSeq: 0, count: 10) { list, nextSeq, isFinished in list.forEach { item in print(item.description) }} fail: { code, desc in print("getConversationList fail, \\(code), \\(desc)")}V2TIMConversationListFilter *filter = [[V2TIMConversationListFilter alloc] init];filter.hasUnreadCount = YES;[[V2TIMManager sharedInstance] getConversationListByFilter:filter nextSeq:0 count:50 succ:^(NSArray<V2TIMConversation *> *list, uint64_t nextSeq, BOOL isFinished) { // 获取会话列表成功,list 为会话列表} fail:^(int code, NSString *desc) { // 获取会话列表失败}];template <class T>class ValueCallback final : public V2TIMValueCallback<T> {public: using SuccessCallback = std::function<void(const T&)>; using ErrorCallback = std::function<void(int, const V2TIMString&)>; ValueCallback() = default; ~ValueCallback() override = default; void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) { success_callback_ = std::move(success_callback); error_callback_ = std::move(error_callback); } void OnSuccess(const T& value) override { if (success_callback_) { success_callback_(value); } } void OnError(int error_code, const V2TIMString& error_message) override { if (error_callback_) { error_callback_(error_code, error_message); } }private: SuccessCallback success_callback_; ErrorCallback error_callback_;};V2TIMConversationListFilter filter;filter.hasUnreadCount = true;auto callback = new ValueCallback<V2TIMConversationResult>{};callback->SetCallback( [=](const V2TIMConversationResult& conversationResult) { // 获取会话列表成功 delete callback; }, [=](int error_code, const V2TIMString& error_message) { // 获取会话列表失败 delete callback; });V2TIMManager::GetInstance()->GetConversationManager()->GetConversationListByFilter(filter, 0, 50, callback);

九、拉取含有群 @ 消息的会话

JavaSwiftObjective-CC++V2TIMConversationListFilter filter = new V2TIMConversationListFilter();filter.setHasGroupAtInfo(true);V2TIMManager.getConversationManager().getConversationListByFilter(filter, 0, 50, new V2TIMValueCallback<V2TIMConversationResult>() { @Override public void onSuccess(V2TIMConversationResult v2TIMConversationResult) { // 获取会话列表成功 } @Override public void onError(int code, String desc) { // 获取会话列表失败 }});let filter = V2TIMConversationListFilter()filter.hasGroupAtInfo = true;V2TIMManager.shared.getConversationListByFilter(filter: filter, nextSeq: 0, count: 10) { list, nextSeq, isFinished in list.forEach { item in print(item.description) }} fail: { code, desc in print("getConversationList fail, \\(code), \\(desc)")}V2TIMConversationListFilter *filter = [[V2TIMConversationListFilter alloc] init];filter.hasGroupAtInfo = YES;[[V2TIMManager sharedInstance] getConversationListByFilter:filter nextSeq:0 count:50 succ:^(NSArray<V2TIMConversation *> *list, uint64_t nextSeq, BOOL isFinished) { // 获取会话列表成功,list 为会话列表} fail:^(int code, NSString *desc) { // 获取会话列表失败}];template <class T>class ValueCallback final : public V2TIMValueCallback<T> {public: using SuccessCallback = std::function<void(const T&)>; using ErrorCallback = std::function<void(int, const V2TIMString&)>; ValueCallback() = default; ~ValueCallback() override = default; void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) { success_callback_ = std::move(success_callback); error_callback_ = std::move(error_callback); } void OnSuccess(const T& value) override { if (success_callback_) { success_callback_(value); } } void OnError(int error_code, const V2TIMString& error_message) override { if (error_callback_) { error_callback_(error_code, error_message); } }private: SuccessCallback success_callback_; ErrorCallback error_callback_;};V2TIMConversationListFilter filter;filter.hasGroupAtInfo = true;auto callback = new ValueCallback<V2TIMConversationResult>{};callback->SetCallback( [=](const V2TIMConversationResult& conversationResult) { // 获取会话列表成功 delete callback; }, [=](int error_code, const V2TIMString& error_message) { // 获取会话列表失败 delete callback; });V2TIMManager::GetInstance()->GetConversationManager()->GetConversationListByFilter(filter, 0, 50, callback);

十、会话列表排序

会话列表始终按照 V2TIMConversation.orderKey 从大到小的顺序排列,orderKey 会随着会话的更新依次递增。

常见引起 orderKey 递增的操作有:收发消息(也即 lastMessage 发生变化)、置顶/取消置顶。

当会话的 lastMessage 的时间顺序与 orderKey 不一致时,以 orderKey 顺序为准。

十一、会话列表更新

IM SDK 会在登录成功后、用户上线后、以及断线重连后,自动更新会话列表。
为了获取会话列表的更新,你需要操作如下几步:

1. 添加会话监听器。

2. 接收会话变更通知并处理。

3. 移除会话监听器。非必须,可按照业务逻辑按需调用。

十二、添加会话监听器

你可以调用 addConversationListener(Java / Swift / Objective-C / C++)添加会话监听器。添加监听器后,你才能接收到会话变更事件。

示例代码如下:

JavaSwiftObjective-CC++V2TIMManager.getConversationManager().addConversationListener(conversationListener);//V2TIMConversationListener 协议V2TIMManager.shared.addConversationListener(listener: self)// self 为 id<V2TIMConversationListener> 类型[[V2TIMManager sharedInstance] addConversationListener:self];class ConversationListener final : public V2TIMConversationListener { // 成员 …};// 添加会话事件监听器,注意在移除监听器之前需要保持 conversationListener 的生命期,以免接收不到事件回调ConversationListener conversationListener;V2TIMManager::GetInstance()->GetConversationManager()->AddConversationListener(&conversationListener);

十三、会话新增变更通知

你可以在 V2TIMConversationListener(Java / Swift / Objective-C / C++)中的事件,获取会话列表变更的通知。

目前 IM SDK 支持的会话变更事件有:

事件 说明 建议
onSyncServerStart 同步服务器会话开始 SDK 会在登录成功、用户上线、断网重连后自动同步服务器会话,你可以监听这个事件做一些 UI 进度展示操作。
onSyncServerFinish 同步服务器会话完成 如果会话有变更,会通过 onNewConversation/onConversationChanged 回调告知。
onSyncServerFailed 同步服务器会话失败 你可以监听这个事件做一些 UI 异常展示操作。
onNewConversation 有会话新增 例如收到一个新同事发来的单聊消息、被拉入了一个新的群组中等,此时可以重新对会话列表做排序。
onConversationChanged 有会话更新 例如未读计数发生变化、最后一条消息被更新等,此时可以重新对会话列表做排序。
onConversationDeleted 有会话被删除 详情请参考 删除会话。7.2.4123 及以上版本支持。
onTotalUnreadMessageCountChanged 会话未读总数变更通知 详情请参考 会话未读数。5.3.425 及以上版本支持。
onUnreadMessageCountChangedByFilter 过滤条件下未读总数变更通知 详情请参考 会话未读数。7.0.3754 及以上版本支持。

注意:1. 为保证会话列表顺序符合最后一条消息的排序原则,每次会话变更/新增后,你需要对数据源重新排序。

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

示例代码如下:

JavaSwiftObjective-CC++// 监听会话的回调V2TIMConversationListener conversationListener = new V2TIMConversationListener() { @Override public void onSyncServerStart() { Log.i("imsdk", "onSyncServerStart"); } @Override public void onSyncServerFinish() { Log.i("imsdk", "onSyncServerFinish"); } @Override public void onSyncServerFailed() { Log.i("imsdk", "onSyncServerFailed"); } @Override public void onNewConversation(List<V2TIMConversation> conversationList) { Log.i("imsdk", "onNewConversation"); } @Override public void onConversationChanged(List<V2TIMConversation> conversationList) { Log.i("imsdk", "onConversationChanged"); } @Override public void onConversationDeleted(List<String> conversationIDList) { Log.i("imsdk", "onConversationDeleted"); } @Override public void onTotalUnreadMessageCountChanged(long totalUnreadCount) { Log.i("imsdk", "onTotalUnreadMessageCountChanged"); } @Override public void onUnreadMessageCountChangedByFilter(V2TIMConversationListFilter filter, long totalUnreadCount) { Log.i("imsdk", "onUnreadMessageCountChangedByFilter"); }};func onSyncServerStart() { // 同步服务器会话开始}func onSyncServerFinish() { // 同步服务器会话结束}func onSyncServerFailed() { // 同步服务器会话失败}func onNewConversation(conversationList: Array<V2TIMConversation>) { // 收到会话新增通知,conversationList 为新增的会话 conversationList.forEach { item in print(item.description) }}func onConversationChanged(conversationList: Array<V2TIMConversation>) { // 收到会话变更通知,conversationList 中为变更后的会话对象 conversationList.forEach { item in print(item.description) }}func onConversationDeleted(conversationIDList: Array<String>) { // 会话被删除}func onTotalUnreadMessageCountChanged(totalUnreadCount: UInt) { // 会话未读总数变化 print("\\(totalUnreadCount)")}func onUnreadMessageCountChangedByFilter(filter: V2TIMConversationListFilter, totalUnreadCount: UInt) { // 过滤条件下的会话未读总数变化 print("\\(filter), count:\\(totalUnreadCount)")}- (void)onSyncServerStart { // 同步服务器会话开始}- (void)onSyncServerFinish { // 同步服务器会话结束}- (void)onSyncServerFailed { // 同步服务器会话失败}- (void)onNewConversation:(NSArray<V2TIMConversation*> *)conversationList { // 收到会话新增通知,conversationList 为新增的会话 [self updateConversation:conversationList];}- (void)onConversationChanged:(NSArray<V2TIMConversation*> *)conversationList { // 收到会话变更通知,conversationList 中为变更后的会话对象 [self updateConversation:conversationList];}- (void)onConversationDeleted:(NSArray<NSString *> *)conversationIDList { // 会话被删除}- (void)onTotalUnreadMessageCountChanged:(UInt64) totalUnreadCount { // 会话未读总数变化}- (void)onUnreadMessageCountChangedByFilter:(V2TIMConversationListFilter *)filter totalUnreadCount:(UInt64)totalUnreadCount { // 过滤条件下的会话未读总数变化}- (void)updateConversation:(NSArray *)convList { // 更新 UI 会话列表,如果 UI 会话列表已经存在该新增/变更的会话,就替换之;如果没有,就新增一个会话对象 for (int i = 0 ; i < convList.count ; ++ i) { V2TIMConversation *conv = convList[i]; BOOL isExit = NO; for (int j = 0; j < self.localConvList.count; ++ j) { V2TIMConversation *localConv = self.localConvList[j]; if ([localConv.conversationID isEqualToString:conv.conversationID]) { // UI 会话列表有更新的会话,直接替换 [self.localConvList replaceObjectAtIndex:j withObject:conv]; isExit = YES; break; } } // UI 会话列表没有更新的会话,直接新增 if (!isExit) { [self.localConvList addObject:conv]; } } // 重新对 UI 会话列表做排序 [self sortDataList:dataList]; self.dataList = dataList;}class ConversationListener final : public V2TIMConversationListener {public: ConversationListener() = default; ~ConversationListener() override = default; void OnSyncServerStart() override { // 同步服务器会话开始 } void OnSyncServerFinish() override { // 同步服务器会话结束 } void OnSyncServerFailed() override { // 同步服务器会话失败 } void OnNewConversation(const V2TIMConversationVector& conversationList) override { // 收到会话新增通知 } void OnConversationChanged(const V2TIMConversationVector& conversationList) override { // 收到会话变更通知 } void OnConversationDeleted(const V2TIMStringVector &conversationIDList) override { // 收到会话被删除通知 } void OnTotalUnreadMessageCountChanged(uint64_t totalUnreadCount) override { // 会话未读总数变更通知 } void OnUnreadMessageCountChangedByFilter(const V2TIMConversationListFilter &filter, uint64_t totalUnreadCount) { // 过滤条件下会话未读总数变更通知 }};// 添加会话事件监听器,注意在移除监听器之前需要保持 conversationListener 的生命期,以免接收不到事件回调ConversationListener conversationListener;V2TIMManager::GetInstance()->GetConversationManager()->AddConversationListener(&conversationListener);

十四、移除会话监听器

你可以调用 removeConversationListener(Java / Swift / Objective-C / C++ )移除会话监听器。移除后,你将无法再接收到会话变更事件。
该步骤不是必须的,你可以按照自己的业务逻辑按需调用。

示例代码如下:

JavaSwiftObjective-CC++V2TIMManager.getConversationManager().removeConversationListener(conversationListener);V2TIMManager.shared.removeConversationListener(listener: self)// self 为 id<V2TIMConversationListener> 类型[[V2TIMManager sharedInstance] removeConversationListener:self];class ConversationListener final : public V2TIMConversationListener { // 成员 …};// conversationListener 是 ConversationListener 的实例V2TIMManager::GetInstance()->GetConversationManager()->RemoveConversationListener(&conversationListener);

十五、发送不更新 lastMessage 的消息

会话列表界面,通常需要展示每个会话的最新一条消息预览及发送时间,此时你可以使用 V2TIMConversation 的 lastMessage 作为数据源实现。
但是某些场景下,如果你不希望一些消息(例如系统提示等)显示为会话的最新消息,可以在 sendMessage 时设置 isExcludedFromLastMessage 为 false/NO。

发送消息 sendMessage 的使用参考:发送消息。

注意:说明:

注意:isExcludedFromLastMessage 参数仅增强版 SDK 5.4.666 及以上版本支持。

示例代码如下:

JavaSwiftObjective-CC++// 创建消息对象V2TIMMessage v2TIMMessage = V2TIMManager.getMessageManager().createTextMessage(content);// 设置不更新会话 lastMessagev2TIMMessage.setExcludedFromLastMessage(true);// 发送消息V2TIMManager.getMessageManager().sendMessage(v2TIMMessage, "userID", null, V2TIMMessage.V2TIM_PRIORITY_DEFAULT, false, null, new V2TIMSendCallback<V2TIMMessage>() { @Override public void onSuccess(V2TIMMessage v2TIMMessage) { Log.i("imsdk", "success"); } @Override public void onProgress(int progress) { Log.i("imsdk", "progress:" + progress); } @Override public void onError(int code, String desc) { Log.i("imsdk", "failure, code:" + code + ", desc:" + desc); }});// 创建消息对象if let message = V2TIMManager.shared.createTextMessage(text: "text") { // 设置不计入会话 lastMessage 的标记 message.isExcludedFromLastMessage = true // 发送消息 V2TIMManager.shared.sendMessage(message: message, receiver: "userA", groupID: nil, priority: .V2TIM_PRIORITY_NORMAL, onlineUserOnly: false, offlinePushInfo: nil, progress: { progress in // 发送进度 }, succ: { // 消息发送成功 }, fail: { code, desc in // 消息发送失败 })}// 创建消息对象V2TIMMessage *message = [V2TIMManager.sharedInstance createTextMessage:content];// 设置不计入会话 lastMessage 的标记message.isExcludedFromLastMessage = YES;// 发送消息[V2TIMManager.sharedInstance sendMessage:message receiver:@"userA" groupID:nil priority:V2TIM_PRIORITY_NORMAL onlineUserOnly:NO offlinePushInfo:nil progress:^(uint32_t progress) { // 发送进度} succ:^{ // 消息发送成功} fail:^(int code, NSString *desc) { // 消息发送失败}];class SendCallback final : public V2TIMSendCallback {public: using SuccessCallback = std::function<void(const V2TIMMessage&)>; using ErrorCallback = std::function<void(int, const V2TIMString&)>; using ProgressCallback = std::function<void(uint32_t)>; SendCallback() = default; ~SendCallback() override = default; void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback, ProgressCallback progress_callback) { success_callback_ = std::move(success_callback); error_callback_ = std::move(error_callback); progress_callback_ = std::move(progress_callback); } void OnSuccess(const V2TIMMessage& message) override { if (success_callback_) { success_callback_(message); } } void OnError(int error_code, const V2TIMString& error_message) override { if (error_callback_) { error_callback_(error_code, error_message); } } void OnProgress(uint32_t progress) override { if (progress_callback_) { progress_callback_(progress); } }private: SuccessCallback success_callback_; ErrorCallback error_callback_; ProgressCallback progress_callback_;};// 创建消息对象V2TIMMessage message = V2TIMManager::GetInstance()->GetMessageManager()->CreateTextMessage(u8"content");// 设置不更新会话 lastMessagemessage.isExcludedFromLastMessage = true;auto callback = new SendCallback{};callback->SetCallback([=](const V2TIMMessage& message) { delete callback; }, [=](int error_code, const V2TIMString& error_message) { delete callback; }, [=](uint32_t progress) {});V2TIMManager::GetInstance()->GetMessageManager()->SendMessage( message, u8"userID", {}, V2TIMMessagePriority::V2TIM_PRIORITY_NORMAL, false, {}, callback);

赞 (0)
上一篇 4天前
下一篇 4天前