-
Notifications
You must be signed in to change notification settings - Fork 27
4.即时通讯 1 基本功能
即时通讯(Instant Messaging,简称 IM)是一种通过网络进行实时通信的系统,允许两人或者多人使用网络即时的传递文字消息、文件、语音与视频交流(来自维基百科的解释)。LeanCloud 即时通讯服务,提供了全面的 IM 能力,可以帮助开发者在自己产品中快速集成 QQ 或微信的功能,如:
- 终端用户实时在线沟通,发送文字、语音、视频、位置信息等等多媒体消息;
- 大型聊天室,如网红直播间和球迷论坛的弹幕互动;
- 公众号的全局消息推送与互动;
- 在线客服,等等。
下面我们以一系列简单的例子来逐步说明 LenaCloud 即时通讯的使用方法,先从一对一单聊入手。
为了节省资源和移动端电量,LeanCloud 的即时通讯是与推送服务共享同一条长链接的,所以 Android 平台要使用即时通讯,首先必须满足以下两个前提:
-
AndroidManifest.xml
文件中增加PushService
和各种必要权限的声明,如下所示,也可参考文档:
<!-- 基础模块(必须加入以下声明)START -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 基础模块 END -->
<application
...
android:name=".MyLeanCloudApp" >
<!-- 即时通讯模块、推送(均需要加入以下声明) START -->
<!-- 即时通讯模块、推送都要使用 PushService -->
<service android:name="cn.leancloud.push.PushService"/>
<receiver android:name="cn.leancloud.push.AVBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.USER_PRESENT"/>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<!-- 即时通讯模块、推送 END -->
<!-- 反馈组件 END -->
</application>
- 程序启动的时候,同时启动
PushService
,也可参考文档; 通过调用以下代码启动推送服务,同时设置默认打开的 Activity。
// 设置默认打开的 Activity
PushService.setDefaultPushCallback(this, PushDemoActivity.class);
Tom 和 Jerry 是一对好友,Tom 时常要拉着 Jerry 聊聊日常的工作、生活感受。这时候该如何使用即时通讯 SDK 完成这一需求呢?
在所有的聊天场景里,都少不了参与者——「用户」这一核心角色,在 LeanCloud 即时通讯系统中,一个AVIMClient
对象代表一个实际的用户,我们首先要为每一个用户创建一个属于他的AVIMClient
实例,方法如下:
// Tom 用自己的名字作为clientId,获取 AVIMClient 对象实例
AVIMClient client = AVIMClient.getInstance("Tom");
AVIMClient
的 getInstance(String clientId)
方法,可以通过传入一个字符串 clientId
,获得唯一确定的实例,也即是说只要传入的 clientId
不变,多次调用时得到的都会是同一个实例对象。在 LeanCloud 即时通讯服务里面,clientId
代表实际产品中的一个用户,它必须满足如下要求:
- clientId 不能为空,也不能超过 64 个字符;
- clientId 由产品自己解释,应用需要自己保证 clientId 是全局唯一的。如果两个不同用户使用相同的 clientId 登录会被认为是同一个即时通讯用户,会导致消息串发。
通过 getInstance
得到 AVIMClient 实例,这时候还不能马上开始聊天,因为该实例还处于断网状态。AVIMClient 一共有三种状态:
- AVIMClientStatusNone:这是 AVIMClient 的初始状态,表示此 client 尚未登录。
- AVIMClientStatusOpened:登录状态,此时 client 可以正常的收发消息。
- AVIMClientStatusPaused:client 登录之后,由于网络中断而处于连接断开状态,此时无法收发消息。
AVIMClient 实例只有处于登录状态才能开始与其他人的聊天互动,接下来我们来看看如何登录。
AVIMClient 实例通过执行 open
操作可以建立与即时通讯云端的连接,方法如下:
client.open(new AVIMClientCallback() {
@Override
public void done(AVIMClient client, AVIMException e) {
if (null != e) {
// 发生错误,open 失败
} else {
// open 成功,client 此时进入联网状态,接下来就可以收发消息了。
}
}
});
open
操作在整个 client 的使用周期内只需要调用一次,以后就可以一直使用了。
我们把 open 操作叫做「登录」,但是这里的登录与通常进行用户认证的登录并不相同,因为不需要提供任何的用户名/密码,AVIMClient 的登录,只是让客户端与 LeanCloud 即时通讯云端建立连接,从而开始进入下面实际的消息交互环节。
Tom 要给 Jerry 发送消息,首先需要创建一个包含两个人的「对话(AVIMConversation)」。「对话(AVIMConversation)」是 LeanCloud 即时通讯系统里另一个核心概念,和实际生活中的聊天室、频道、房间等对应,表示若干用户组成的一个聊天群组。LeanCloud 即时通讯系统里,所有的聊天消息、成员事件都是围绕「对话(AVIMConversation)」进行的。
在一个已经登录的 AVIMClient 上调用 createConversation
方法,可以创建一个对话,示例如下:
client.createConversation(Arrays.asList("Jerry"), "Tom & Jerry", null, new AVIMConversationCreatedCallback() {
@Override
public void done(AVIMConversation conversation, AVIMException e) {
if (null != e) {
// 发生错误,创建失败
} else {
// 创建成功,conversation 就是生成的对话实例。
}
}
});
createConversation 方法的参数有:
- List conversationMembers(成员列表)。可以在创建对话的时候,就指定需要的成员,这些成员会收到邀请加入对话的通知。当前登录用户即为对话的创建者,也会被自动加入到成员列表之中。在创建对话时成员列表也可以为空,可以将来再加入更多成员。
- String name(对话名字)。你可以为每一个对话都指定一个便于识别的名字(例如聊天室),也可以不指定(例如一对一的单聊)。
- Map<String, Object> attributes(对话附属属性)。允许你给对话指定附加的属性,以 key-value 的形式存储,内容由应用自己解释。对话属性允许为空。
- AVIMConversationCreatedCallback callback(结果回调函数)。如上例所示,创建对话的结果通过回调函数通知创建者。
当对话创建成功之后,你可以在 LeanCloud 控制台 > 存储 > 数据 > _Conversation
中看到其结果。_Conversation
表中各字段的含义如下:
名称 | 类型 | 描述 |
---|---|---|
name | String | 对话的名字 |
m | Array | 对话中成员的列表 |
attr | Object | 开发者设置的对话的自定义属性 |
c | String | 对话的创建者的 ClientId |
lm | Date | 对话中最后一条消息发送的时间 |
mu | Array | 对话中设置了静音的成员。Android 设备需要先开启混合推送服务,才能接收离线消息推送。 |
对话创建好之后,我们就可以往对话中发送消息了。
扩展阅读 —— 唯一对话
上面代码演示了 Tom 希望和 Jerry 聊天时,就新建一个包含两人的对话,而所有的聊天消息都是从属于某一个对话的,所以这样也带来一个问题:每次都新建一个对话的话,我们是会遗失历史消息的。如果希望复用同一个已经存在的对话(也就是要求 createConversation 的结果是新建或者返回已有的对话),该怎么做呢?
AVIMClient还有另一个方法:
public void createConversation(final List<String> conversationMembers, String name, final Map<String, Object> attributes, final boolean isUnique, final AVIMConversationCreatedCallback callback)
新增了一个
isUnique
参数,表示如果已经存在符合条件的对话,是否返回已有对话实例。
为 false 时,则一直为创建新的对话。isUnique 默认为 false。
为 true 时,则先查询,如果已有符合条件的对话(仅 conversationMembers 为有效查询条件),则返回已有的,否则,创建新的并返回。
LeanCloud 即时通讯服务默认支持多种消息类型:文本,图像,语音,视频,位置,二进制消息,等等。后面会有详细说明,现在我们先试试让 Tom 给 Jerry 发送一条文本消息。示例如下:
// 构建文本消息
AVIMTextMessage msg = new AVIMTextMessage();
msg.setText("耗子,起床!");
// 把消息发到对话里
conversation.sendMessage(msg, new AVIMConversationCallback() {
@Override
public void done(AVIMException e) {
if (null != e) {
// 发生错误,消息没有发送出去。
} else {
// 消息发送成功。
}
}
});
AVIMConversation#sendMessage 方法支持两个参数:
- AVIMMessage message(待发送的消息)。AVIMTextMessage 是 AVIMMessage 的一个子类。
- AVIMConversationCallback callback(回调函数)。通过该回调函数通知调用者发送操作是否成功。
现在 Tom 这一方完成了一系列操作,给 Jerry 发过去了一条消息,那 Jerry 该如何接收并响应这条消息呢?
Jerry 要接收到别人发给他的消息,和 Tom 一样,他首先也要创建自己的 AVIMClient 实例并登录聊天系统,之后因为消息接收方是被动接受系统的通知,所以 Jerry 需要注册一些通知/事件响应函数,才能及时接收到实时消息。
LeanCloud 即时通讯服务中主要包含两大类事件通知:成员变化的事件通知和聊天消息的通知。
诸如「你被 xx 邀请加入 xx 对话」、「xx 成员被 xx 邀请加入 xx 对话」、「你被 xx 踢出 xx 对话」、「xx 成员被 xx 踢出 xx 对话」等等,主要是当前用户被邀请加入 / 踢出某个对话,以及当前用户参与的对话中发生了新的成员变化事件。对话成员变化的相关通知在 AVIMConversationEventHandler 抽象类中进行了定义,开发者必须实现的方法如下:
public abstract class AVIMConversationEventHandler {
/**
* 实现本方法来处理当前用户被邀请到某个聊天对话事件
*
* @param client
* @param conversation 被邀请的聊天对话
* @param operator 邀请你的人
*/
public abstract void onInvited(AVIMClient client, AVIMConversation conversation,
String operator);
/**
* 实现本方法来处理当前用户被踢出某个聊天对话事件
*
* @param client
* @param conversation
* @param kickedBy 踢出你的人
*/
public abstract void onKicked(AVIMClient client, AVIMConversation conversation,
String kickedBy);
/**
* 实现本方法以处理聊天对话中的参与者离开事件
*
* @param client
* @param conversation
* @param members 离开的参与者
* @param kickedBy 离开事件的发动者,有可能是离开的参与者本身
*/
public abstract void onMemberLeft(AVIMClient client,
AVIMConversation conversation, List<String> members, String kickedBy);
/**
* 实现本方法以处理聊天对话中的参与者加入事件
*
* @param client
* @param conversation
* @param members 加入的参与者
* @param invitedBy 加入事件的邀请人,有可能是加入的参与者本身
*/
public abstract void onMemberJoined(AVIMClient client,
AVIMConversation conversation, List<String> members, String invitedBy);
}
开发者需要实现自己的 AVIMConversationEventHandler,并调用 AVIMMessageManager.setConversationEventHandler(conversationEventHandler) 进行设置。完整的示例代码如下:
public class MyConversationEventHandler extends AVIMConversationEventHandler {
public void onInvited(AVIMClient client, AVIMConversation conversation, String operator) {
;
}
public void onKicked(AVIMClient client, AVIMConversation conversation, String kickedBy) {
;
}
public void onMemberLeft(AVIMClient client,
AVIMConversation conversation, List<String> members, String kickedBy) {
;
}
public void onMemberJoined(AVIMClient client,
AVIMConversation conversation, List<String> members, String invitedBy) {
;
}
}
// 设置 handler
AVIMMessageManager.setConversationEventHandler(new MyConversationEventHandler());
当前用户参与对话中的新消息,会通过消息处理 handler 通知用户。MessageHandler 的定义如下:
public abstract class MessageHandler<T extends AVIMMessage> {
public abstract void onMessage(T message, AVIMConversation conversation, AVIMClient client);
public abstract void onMessageReceipt(T message, AVIMConversation conversation, AVIMClient client);
}
其中 onMessage
方法即表示有新消息到达,它的三个参数分别表示关联的消息、对话、client 实例。onMessageReceipt
方法以后会解释,现在先不管。
开发者需要实现自己的 MessageHandler,并调用 AVIMMessageManager.registerDefaultMessageHandler(handler) 来设置全局的消息处理 handler。完整的示例代码如下:
public class MyDefaultMessageHandler<AVIMMessage> extends MessageHandler {
public void onMessage(AVIMMessage message, AVIMConversation conversation, AVIMClient client) {
;
}
public void onMessageReceipt(T message, AVIMConversation conversation, AVIMClient client) {
;
}
}
// 设置 handler
AVIMMessageManager.registerDefaultMessageHandler(new MyDefaultMessageHandler());
扩展阅读 —— 设置不同的消息处理 handler
消息处理的 MessageHandler 在 AVIMMessageManager 中进行注册时有两个不同的方法:
registerDefaultMessageHandler
和registerMessageHandler
。其中registerMessageHandler
支持给特定类型的消息指定特定的处理 handler:public static void registerMessageHandler(Class<? extends AVIMMessage> clazz, MessageHandler<?> handler)
当即时通讯 SDK 收到一条消息的时候,会优先根据消息类型查找与之匹配的特定 messageHandler,如果发现当前没有任何注册的普通的 messageHandler,才会去调用 defaultMessageHandler。
在 AVIMMessageManager 中多次注册 defaultMessageHandler,只有最后一次调用的才是有效的;而通过 registerMessageHandler 注册的 MessageHandler,则是可以同存的。
接下来我们看看如何实现一个稍微复杂一点的聊天场景:多人群聊。与一对一聊天相比,多人群聊在消息收发流程上是完全一致的,这里的差异主要在于成员的添加和删除。
AVIMConversation 上涉及到成员增减的方法有:
操作目的 | 接口名 |
---|---|
自身主动加入 | AVIMConversation#join |
添加其他成员 | AVIMConversation#addMembers |
自身主动退出 | AVIMConversation#quit |
剔除其他成员 | AVIMConversation#kickMembers |
假设 Jerry、Bob、Harry 和 William 的四个人创建了一个多人群聊对话(id:551260efe4b01608686c3e0f),现在 Tom 希望加入其中,其示例代码如下:
AVIMConversation conversation = client.getConversation("551260efe4b01608686c3e0f");
conversation.join(new AVIMConversationCallback(){
@Override
public void done(AVIMException e){
if(null == e){
// 加入成功
}
}
});
Tom 成功加入这个群聊对话之后,该群内的其他成员会收到 onMemberJoined
通知。
假如 Tom 加入 Jerry 四人的群聊对话之后,又想自己退出去,其操作代码如下:
AVIMConversation conversation = client.getConversation("551260efe4b01608686c3e0f");
conversation.quit(new AVIMConversationCallback(){
@Override
public void done(AVIMException e){
if(null == e){
// 退出成功
}
}
});
Tom 成功退群之后,该群内的其他成员会收到 onMemberLeft
通知。
假如 Tom 加入 Jerry 四人的群聊对话之后,还想把大家的好友 Mary 也拉进去,其操作代码如下:
AVIMConversation conversation = client.getConversation("551260efe4b01608686c3e0f");
conversation.addMembers(Arrays.asList("Mary"), new AVIMConversationCallback() {
@Override
public void done(AVIMException e){
if(null == e){
// 邀请成功
}
}
});
只有已经加入到对话里面的用户才可以邀请其他人。
Tom 邀请成功之后,该群内的其他成员会收到 onMemberJoined
通知,Mary 则会收到一条 onInvited
通知。
No. | 邀请者 | 被邀请者 | 其他人 |
---|---|---|---|
1 | 发出请求 addMembers | ||
2 | 收到 onInvited 通知 | ||
3 | 收到 onMemberJoined 通知 | 收到 onMemberJoined 通知 |
假如 Tom 加入之后,Jerry 发现他经常发一些不合适的消息,被群里好几个朋友投诉,他决定把 Tom 踢出当前群聊,其操作代码如下:
AVIMConversation conversation = client.getConversation("551260efe4b01608686c3e0f");
conversation.kickMembers(Arrays.asList("Tom"), new AVIMConversationCallback() {
@Override
public void done(AVIMException e){
if(e==null){
// 踢人成功
}
}
});
与邀请用户一样,只有已经加入到对话里面的用户才可以踢出其他人。
Jerry 操作成功之后,Tom 会收到 onKicked
通知,该群内的其他成员会收到 onMemberLeft
通知。
No. | 操作者(管理员) | 被踢者 | 其他人 |
---|---|---|---|
1 | 发出请求 kickMembers | ||
2 | 收到 onKicked 通知 | ||
3 | 收到 onMemberLeft 通知 | 收到 onMemberLeft 通知 |
从上面例子可以看出,如果一个对话内发生了成员变动,即时通讯云端会实时通知客户端。所以如果客户端能够一直保持在线,并且及时响应云端发过来的通知,那么在应用层通过调用 AVIMConversation#getMembers
方法是能够得到准确的成员列表的,但是对于移动设备来说,产品一直保持在线几乎是不可能的,所以 SDK 中 AVIMConversation#getMembers
返回的成员列表信息并不完全可靠。
要得到最新的成员列表信息,可以先通过更新 AVIMConversation 属性,然后再调用 getMembers
方法获得当前时点的成员列表,示例代码如下:
conversation.fetchInfoInBackground(new AVIMConversationCallback() {
@Override
public void done(AVIMException e) {
if (null != e) {
// 发生错误
} else {
// members is result.
List<String> members = conversation.getMembers();
}
}
});
还有更多的时候,我们不需要获取所有的成员列表详细信息,而只需要知晓对话内成员数量,则可以调用 AVIMConversation.getMemberCount
这个方法,来实时查询成员数量。其示例代码为:
conversation.getMemberCounter(new AVIMConversationMemberCountCallback() {
@Override
public void done(Integer memberCount, AVIMException e) {
if (null != e) {
// 发生错误
} else {
// memberCount is result.
}
}
});
扩展阅读 — 对话成员角色管理
在上面的例子中我们可以看到,在默认情况下,给对话增减成员并不需要特别的权限,所有参与其中的用户都可以进行操作。但很多时候,我们会给成员分配不同的角色,譬如管理员,我们约定只有管理员才可以邀请或者踢出对话成员;或者,对于一些不受欢迎的用户,仅仅踢出对话还不够,我们希望把他们拉入一个黑名单中,永远也无法进入对话并发言。
类似的功能,可以参考后面的章节:高级功能之聊天模式与角色管理 。
前面的例子都是基于普通文本消息的,LeanCloud 即时通讯服务则支持多种消息类型:
- 文本消息:AVIMTextMessage
- 图像消息:AVIMImageMessage
- 音频消息:AVIMAudioMessage
- 视频消息:AVIMVideoMessage
- 文件消息:AVIMFileMessage
- 位置消息:AVIMLocationMessage
- 二进制消息:AVIMBinaryMessage
下面我们来逐一演示这些消息的发送和接收流程。
可以从系统提供的拍照 API 或本地媒体库中获取完整的图像数据,也可以用网络上有效的图像 URL,来构造图像消息。
通过本地文件或系统拍照 API 获取图像数据,构造图像消息的示例如下:
String filePath = ... // 本地文件路径
AVIMImageMessage picture = new AVIMImageMessage(filePath);
picture.setText("发自我的小米"); // 可以为图像增加多项说明信息
Map < String, Object > attributes = new HashMap < String, Object > ();
attributes.put("location", "旧金山");
picture.setAttribute(attributes);
通过直接使用网络图片,例如从微博上复制的一个图像链接来创建图像消息,其示例如下:
AVFile file =new AVFile("萌妹子","http://pic2.zhimg.com/6c10e6053c739ed0ce676a0aff15cf1c.gif", null);
AVIMImageMessage picture = new AVIMImageMessage(file);
picture.setText("萌妹子一枚");
发送图像消息时,直接把上面生成的图像消息实例当做参数交由 AVIMConversation 发送出去即可:
conversation.sendMessage(picture, new AVIMConversationCallback() {
@Override
public void done(AVIMException e) {
if (null == e) {
// 发送成功
}
}
});
即时通讯 SDK 内部,对不同来源的图像消息的处理流程是完全不一样的:
- 通过提供图像完整数据构造的消息:SDK 获取了完整的图像数据流,先上传文件到云端,再将文件的元数据以及 URL 等一并包装,发送出去。
- 通过引用网络图像构造的消息:SDK 并没有将图像实际上传到云端,而仅仅把 URL 包装在消息体内发送出去,这种情况下接收方是无法从消息体中获取图像的元信息数据,但是接收方可以自行通过客户端技术去分析图片的格式、大小、长宽之类的元数据。
与图像消息类似,音频消息也支持通过两种不同的来源创建:
- 通过本地文件或者系统 API 提供完整音频数据创建,例如:
AVFile file = AVFile.withAbsoluteLocalPath("忐忑.mp3",localFilePath);
AVIMAudioMessage msg = new AVIMAudioMessage(file);
msg.setText("听听人类的神曲~");
- 通过引用网络音频文件创建,例如:
AVFile file = new AVFile("music", "http://ac-lhzo7z96.clouddn.com/1427444393952", null);
AVIMAudioMessage msg = new AVIMAudioMessage(file);
音频消息的发送也与图像类似,在此不再赘述。
与图像消息类似,视频消息也支持通过两种不同的来源创建:
- 通过本地文件或者系统 API 提供完整视频数据创建,例如:
AVFile file = AVFile.withAbsoluteLocalPath("bbc_奶酪.mp4", localFilePath);
AVIMVideoMessage msg = new AVIMVideoMessage(file);
msg.setText("听听人类的神曲~");
- 通过引用网络视频文件创建,例如:
AVFile file = new AVFile("video", "http://ac-lhzo7z96.clouddn.com/1427267336319", null);
AVIMVideoMessage msg = new AVIMVideoMessage(file);
视频消息的发送也与图像类似,在此不再赘述。
图像、音频、视频是三种特殊的文件消息,LeanCloud 也支持发送普通的文件消息(例如一个 pdf 文档,一份代码压缩包等)。文件消息支持两种创建方式:
- 通过本地文件或者系统 API 提供完整视频数据创建,例如:
AVFile file = AVFile.withAbsoluteLocalPath("bbc_奶酪.zip", localFilePath);
AVIMFileMessage msg = new AVIMFileMessage(file);
msg.setText("最新的压缩包~");
- 通过引用网络视频文件创建,例如:
AVFile file = new AVFile("zip", "http://ac-lhzo7z96.clouddn.com/1427267336319", null);
AVIMFileMessage msg = new AVIMFileMessage(file);
文件消息的发送也与图像类似,在此不再赘述。
地址位置消息的构建方式如下:
AVIMLocationMessage msg = new AVIMLocationMessage();
msg.setLocation(new AVGeoPoint(45.0,34.0));
msg.setText("新开的蛋糕店!耗子咱们有福了…");
地理位置消息的发送也与图像类似,在此不再赘述。
一个对话的消息记录会在云端保留 6 个月,也就是说一个对话可以查询到半年之内的历史消息记录,同时 LeanCloud 即时通讯服务也允许开发者通过额外付费来延长这一期限。 与此同时,即时通讯 SDK 则是有本地消息缓存的,这一缓存没有时间限制。
AVIMConversation 类中提供了多种方法来获取该对话中的历史消息。
AVIMConversation 提供了最简单的方法,可以查询对话中最新的 20 条消息记录(如果不足 20 条则以实际条数为准):
void queryMessages(final AVIMMessagesQueryCallback callback)
如果想一次获得更多的结果,可以使用另一个方法:
void queryMessages(final int limit, final AVIMMessagesQueryCallback callback)
这里 limit 就是期望的消息结果数量,有效值在 1 - 200(含)之间。
考虑到网络状况以及本地缓存的存在,即时通讯 SDK 也额外提供了强制从服务端或本地缓存查询的接口(不过一般情况下不建议开发者调用):
/**
* 强制从服务器端拉取最新消息
*/
void queryMessagesFromServer(int limit, final AVIMMessagesQueryCallback callback);
/**
* 强制从本地缓存中拉取消息
*/
void queryMessagesFromCache(int limit, AVIMMessagesQueryCallback callback);
上面的消息都是完全按照时间先后顺序来查询,有的产品中需要按照消息类型来查询,譬如只希望展示当前对话中的所有图像消息,AVIMConversation 也提供了接口支持这一需求:
void queryMessagesByType(int msgType, int limit, final AVIMMessagesQueryCallback callback)
开发者可以指定特定的消息类型(具体请参看 AVIMMessageType
里的定义),以及希望获取的结果集大小,来查询特定的历史消息。注意,这个操作总是会从云端来获取消息。
上面的例子都只能获取最新的若干条消息记录,如果我们希望分页,例如客户端根据用户的滑动操作来加载更多历史消息,就需要使用分页查询的接口了。
LeanCloud 即时通讯云端在存储历史消息的时候,是通过 <conversationid,messageId,messageTimestamp>
这样的三元组来唯一定位一条消息的,所以在对历史消息进行分页查询的时候,我们需要明确查询的起点消息(需要提供 messageId 和 messageTimestamp),以及单页消息的数量多少,其接口定义如下:
void queryMessages(final String messageId, final long timestamp, final int limit, final AVIMMessagesQueryCallback callback)
返回的消息列表中不会包含起点消息。如果我们不指定 messageId(为空) 和 timestamp(为 0),那么这个函数就等同于
void queryMessages(final int limit, final AVIMMessagesQueryCallback callback)
了;如果我们在获取一页数据之后,取最老消息记录的 messageId 和 timestamp 继续调用分页查询方法,如此重复就可以继续获取更老的历史消息了。
与分类查询历史消息的接口对应,我们也提供了对特定类型消息的分页查询接口,其定义如下:
void queryMessagesByType(int msgType, final String msgId, final long timestamp, final int limit, final AVIMMessagesQueryCallback callback)
与前面的方法类似,这里只是增加了 msgType
参数,表示指定的消息类型。
上面的方法只支持按时间先后顺序查询更老的历史消息,AVIMConversation 还提供了方法,支持按照不同的方向(向前,即由新到旧,或者向后,即由旧到新)、起始区间(开闭)来查询历史消息,这是一种更加自由和强大的方式,其定义如下:
/**
* 根据指定的区间来查询历史消息,可以指定区间开闭、查询方向以及最大条目限制
* @param interval - 区间,由起止 AVIMMessageIntervalBound 组成
* @param direction - 查询方向,支持向前(AVIMMessageQueryDirection.AVIMMessageQueryDirectionFromNewToOld)
* 或向后(AVIMMessageQueryDirection.AVIMMessageQueryDirectionFromOldToNew)查询
* @param limit - 结果最大条目限制
* @param callback - 结果回调函数
*/
public void queryMessages(final AVIMMessageInterval interval, AVIMMessageQueryDirection direction, final int limit,
final AVIMMessagesQueryCallback callback);
扩展阅读 —— 自定义消息
LeanCloud 即时通讯服务提供了默认的几种多媒体消息,但是如果产品中要实现更多的其他样式的消息,例如红包消息,这时候该怎么办呢?我们也提供了自定义消息类型的扩展机制,具体内容可以参考下一章:高级功能之消息与状态。
到目前为止,我们熟悉了最基本的聊天流程,如果你想了解更多的功能和用法,请参看下一章。本文档中提及的完整代码,可以参考文件 即时通讯-基本功能 demo。