Android&iOS&Windows&Mac

最近更新时间:2024-12-26 12:26:34

我的收藏

功能描述

用户在登录 App 后,可以像微信或 QQ 那样展示最近会话列表,方便找到目标会话。会话列表如下图所示:

会话列表功能主要分为获取会话列表、处理会话列表更新。本文将为您介绍具体的实现细节。

获取会话列表基础接口

您可以调用 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 这么多)。
示例代码如下:
Java
Swift
Objective-C
C++
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(会话拉取是否完成)。
如果 isFinishedtrue,表示所有会话已经拉取完成。
如果 isFinishedfalse,表示还有更多的会话可以拉取。此时并不意味着要立刻开始拉取 “下一页” 的会话列表。在常见的软件中,分页拉取通常由用户的滑动操作触发的,用户每上拉一次会话列表就触发一次分页拉取。
3. 当用户继续上拉会话列表时,如果还有更多的会话可以拉取,可以继续调用 getConversationList 接口,并传入新一轮的 nextSeq(数值来自上一次拉取返回的 V2TIMConversationResult 对象)和 count 参数。
4. 重复执行【步骤 3】直至 isFinished 返回 true。
示例代码如下:
Java
Swift
Objective-C
C++
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 = false
var 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:返回所有会话

拉取单聊或群聊会话

Java
Swift
Objective-C
C++
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);

拉取指定分组会话

Java
Swift
Objective-C
C++
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);

拉取指定标记会话

Java
Swift
Objective-C
C++
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);

拉取含有未读数的会话

Java
Swift
Objective-C
C++
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);

拉取含有群 @ 消息的会话

Java
Swift
Objective-C
C++
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. 移除会话监听器。非必须,可按照业务逻辑按需调用。

添加会话监听器

您可以调用 addConversationListenerJava / Swift / Objective-C / C++)添加会话监听器。添加监听器后,您才能接收到会话变更事件。
示例代码如下:
Java
Swift
Objective-C
C++
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);

会话新增变更通知

您可以在 V2TIMConversationListenerJava / 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. 为保证会话列表顺序符合最后一条消息的排序原则,每次会话变更/新增后,您需要对数据源重新排序。
如果您使用 5.5.892 以前的版本,可以使用 lastMessage 排序,但是需要注意处理 lastMessage 为空(例如清空会话消息)的情况。
如果您使用 5.5.892 及以后的版本,使用 orderKey 字段排序。我们强烈建议您升级到 5.5.892 及以后版本。
2. 调用 getConversationList 接口拉取的会话可能已经通过 onNewConversation 回调接口添加到了 UI 会话列表的数据源中。为了避免重复添加同一个会话,您需要在 UI 会话列表数据源中根据 getConversationID 找到相同的会话并做替换。
示例代码如下:
Java
Swift
Objective-C
C++
// 监听会话的回调

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);

移除会话监听器

您可以调用 removeConversationListenerJava / Swift / Objective-C / C++ )移除会话监听器。移除后,您将无法再接收到会话变更事件。 该步骤不是必须的,您可以按照自己的业务逻辑按需调用。
示例代码如下:
Java
Swift
Objective-C
C++
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 的消息

会话列表界面,通常需要展示每个会话的最新一条消息预览及发送时间,此时您可以使用 V2TIMConversationlastMessage 作为数据源实现。 但是某些场景下,如果您不希望一些消息(例如系统提示等)显示为会话的最新消息,可以在 sendMessage 时设置 isExcludedFromLastMessagefalse/NO
发送消息 sendMessage 的使用参考:发送消息
说明:
isExcludedFromLastMessage 参数仅增强版 SDK 5.4.666 及以上版本支持。
示例代码如下:
Java
Swift
Objective-C
C++
// 创建消息对象
V2TIMMessage v2TIMMessage = V2TIMManager.getMessageManager().createTextMessage(content);
// 设置不更新会话 lastMessage
v2TIMMessage.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");
// 设置不更新会话 lastMessage
message.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);