Android 应用APP加入聊天功能
简介
自去年LeanCloud发布实时通信(IM)服务之后,基于用户反馈和工程师对需求的消化和对业务的提炼,上周正式发布了「实时通信2.0」。设计理念依然是「灵活、解耦、可组合、可定制」,具体可以参考《实时通信开发指南》,了解LeanCloud实时通信的基本概念和模型。
下载和安装
可以到LeanCloud官方下载点下载LeanCloudIMSDKv2版本。将下载到的jar包加入工程即可。
一对一的文本聊天
我们先从最简单的环节入手,看看怎么用LeanCloudIMSDKv2实现一对一文本聊天。
初始化
和LeanCloud其他服务一样,实时聊天服务的初始化也是在Application的onCreate方法中进行的:
publicclassMyApplicationextendsApplication{
publicvoidonCreate(){
...
AVOSCloud.initialize(this,"{{appId}}","{{appKey}}");
...
}
}
并且在AndroidManifest.xml中间声明:
<manifest>
...
<application
android:name=".MyApplication"
....>
...
<serviceandroid:name="com.avos.avoscloud.PushService"/>
<receiverandroid:name="com.avos.avoscloud.AVBroadcastReceiver">
<intent-filter>
<actionandroid:name="android.intent.action.BOOT_COMPLETED"/>
<actionandroid:name="android.intent.action.USER_PRESENT"/>
</intent-filter>
</receiver>
...
</application>
</manifest>
接下来我们需要完成用户登录。
登录
假定聊天发起方名叫Tom,为直观起见,我们使用用户名来作为clientId登录聊天系统(LeanCloud云端只要求clientId在应用内唯一即可,具体用什么数据由应用层决定),代码如下:
AVIMClientimClient=AVIMClient.getInstance("Tom");
imClient.open(newIMClientCallback(){
@Override
publicvoiddone(AVIMClientclient,AVExceptione){
if(e){
//出错了,可能是网络问题无法连接LeanCloud云端,请检查网络之后重试。
//此时聊天服务不可用。
}else{
//成功登录,可以开始进行聊天了。
};
}
});
建立对话
假定我们要跟「Bob」这个用户进行聊天,我们先创建一个对话,代码如下:
//下面的代码包含了实际应用中的所有逻辑:查询->创建「对话」。
//先查询一下是否已经存在与「Bob」的私聊对话,可以先忽略这部分代码
List<String>clientIds=newArrayList<String>();
clientIds.add("Tom");
clientIds.add("Bob");
AVIMConversationQueryconversationQuery=imClient.getQuery();
conversationQuery.withMembers(clientIds);
//之前有常量定义:
//intConversationType_OneOne=0;//两个人之间的单聊
//intConversationType_Group=1; //多人之间的群聊
conversationQuery.whereEqualTo("attr.type",ConversationType_OneOne);
conversationQuery.findInBackground(newAVIMConversationQueryCallback(){
@Override
publicvoiddone(List<AVIMConversation>conversations,AVExceptione){
if(null!=e){
//出错了。。。
}elseif(null!=conversations&&conversations.size()>0){
//已经有一个和Bob的对话存在,继续在这一对话中聊天
...
}else{
//不曾和Bob聊过,新建一个对话。!!**这里是重点**!!
Map<String,Object>attr=newHashMap<String,Object>();
attr.put("type",ConversationType_OneOne);
imClient.createConversation(clientIds,attr,newAVIMConversationCreatedCallback(){
@Override
publicvoiddone(AVIMConversationconversation,AVExceptione){
if(null!=conversation){
//成功了!
}
}
});
}
}
});
如何查询「对话」
如你所见,我们创建一个对话的时候,指定了成员(Tom和Bob)和一个额外的属性({type:0})。这些数据保存到云端后,你在控制台->存储->数据里面会看到,_Conversation表中增加了一条记录,新记录的m属性值为["Tom","Bob"],attr属性值为{"type":0}。如你所料,m属性就是对应着成员列表,attr属性就是用户增加的额外属性值(以对象的形式存储)。
与AVObject的检索方法一样,要检索这样的对话,我们需要通过imClient.getQuery()得到一个AVIMConversationQuery实例,然后调用conversationQuery.withMembers()来限定成员列表,调用conversationQuery.whereEqualTo()来限定额外的attr属性。按照AVQuery的惯例,限定额外的type条件的时候需要指定的属性名是attr.type。
发送消息
建立好对话之后,要发送消息是很简单的:
AVIMMessagemessage=newAVIMMessage();
message.setContent("hello");
conversation.sendMessage(message,newAVIMConversationCallback(){
@Override
publicvoiddone(AVExceptione){
if(null!=e){
//出错了。。。
}else{
}
}
});
好了,这样一条消息就发送过去了。但是问题来了,对于「Bob」而言,他怎么才能收到别人发给他的消息呢?
消息接收
在Bob这一端,要能接收到消息,需要如下几步:
1,进行初始化和登录,代码与发送端并无二致;
2,实现自己的AVIMMessageHandler,响应新消息到达通知,主要是如下函数:
publicvoidonMessage(AVIMMessagemessage,AVIMConversationconversation,AVIMClientclient);
对于Tom发过来的消息,要显示出来,我们只需实现onMessage即可,示例代码如下:
classCustomMessageHandlerextendsAVIMMessageHandler{
@Override
publicvoidonMessage(AVIMMessagemessage,AVIMConversationconversation,AVIMClientclient){
//新消息到来了。在这里增加你自己的处理代码。
...
}
}
AVIMMessageManager.registerDefaultMessageHandler(newCustomMessageHandler());
几个主要的回调接口
从上面的例子中可以看到,要接收到别人给你发送的消息,需要实现自己的AVIMMessageHandler类。从v2版开始,LeanCloudIMSDK大量采用回调来反馈操作结果,但是对于一些被动的消息通知,则还是采用接口来实现的,包括:
当前网络出现变化
对话中有新的消息
对话中有新成员加入
对话中有成员离开
被邀请加入某对话
被踢出对话
LeanCloudIMSDK内部使用了三种接口来响应这些事件。
网络事件响应接口(AVIMClientEventHandler)
主要用来处理网络变化事件,主要函数为:
/** *实现本方法以处理网络断开事件 * *@paramclient *@since3.0 */ publicabstractvoidonConnectionPaused(AVIMClientclient); /** *实现本方法以处理网络恢复事件 * *@since3.0 *@paramclient */ publicabstractvoidonConnectionResume(AVIMClientclient);
在网络中断的情况下,所有的消息收发和对话操作都会出现问题。
通过AVIMClient.setClientEventHandler(AVIMClientEventHandlerhandler)可以设定全局的ClientEventHandler。
对话成员变化响应接口(AVIMConversationEventHandler)
主要用来处理对话中成员变化的事件,主要函数为:
/**
*实现本方法以处理聊天对话中的参与者离开事件
*
*@paramclient
*@paramconversation
*@parammembers离开的参与者
*@paramkickedBy离开事件的发动者,有可能是离开的参与者本身
*@since3.0
*/
publicabstractvoidonMemberLeft(AVIMClientclient,
AVIMConversationconversation,List<String>members,StringkickedBy);
/**
*实现本方法以处理聊天对话中的参与者加入事件
*
*@paramclient
*@paramconversation
*@parammembers加入的参与者
*@paraminvitedBy加入事件的邀请人,有可能是加入的参与者本身
*@since3.0
*/
publicabstractvoidonMemberJoined(AVIMClientclient,
AVIMConversationconversation,List<String>members,StringinvitedBy);
/**
*实现本方法来处理当前用户被踢出某个聊天对话事件
*
*@paramclient
*@paramconversation
*@paramkickedBy踢出你的人
*@since3.0
*/
publicabstractvoidonKicked(AVIMClientclient,AVIMConversationconversation,
StringkickedBy);
/**
*实现本方法来处理当前用户被邀请到某个聊天对话事件
*
*@paramclient
*@paramconversation被邀请的聊天对话
*@paramoperator邀请你的人
*@since3.0
*/
publicabstractvoidonInvited(AVIMClientclient,AVIMConversationconversation,
Stringoperator);
通过AVIMMessageManager.setConversationEventHandler(AVIMConversationEventHandlerhandler)可以设置全局的ConversationEventHandler。
消息响应接口(MessageHandler)
主要用来处理新消息到达事件,主要的函数为:
//收到新的消息 @Override publicabstractvoidonMessage(AVIMMessagemessage,AVIMConversationconversation); //自己发送的消息已经被对方接收 @Override publicabstractvoidonMessageReceipt(AVIMMessagemessage,AVIMConversationconversation,AVIMClientclient);
通过AVIMMessageManager.registerDefaultMessageHandler(MessageHandlerhandler)可以设置全局的MessageHandler。
我们实现这三类接口,就可以处理所有的通知消息了(注意:LeanCloudIMSDK内部实现了一个空的AVIMMessageHandler,你可以从这里派生出进行实际处理的handler)。
支持富媒体的聊天消息
上面的代码演示了如何发送简单文本信息,但是现在的交互方式已经越来越多样化,图片、语音、视频已是非常普遍的消息类型。v2版的LeanCloudIMSDK已经可以很好地支持这些富媒体消息,具体说明如下:
基类:AVIMTypedMessage
所有富媒体消息的基类,其声明为
//SDK定义的消息类型,LeanCloudSDK自身使用的类型是负数,所有正数留给开发者自定义扩展类型使用,0作为「没有类型」被保留起来。
enumAVIMReservedMessageType{
UnsupportedMessageType(0),
TextMessageType(-1),
ImageMessageType(-2),
AudioMessageType(-3),
VideoMessageType(-4),
LocationMessageType(-5),
FileMessageType(-6);
};
publicabstractclassAVIMTypedMessageextendsAVIMMessage{
publicAVIMTypedMessage();
publicintgetMessageType();
@Override
publicfinalStringgetContent();
@Override
publicfinalvoidsetContent(Stringcontent);
}
文本消息(AVIMTextMessage)
AVIMTypedMessage子类,表示一般的文本消息,其声明为
@AVIMMessageType(type=-1)
publicclassAVIMTextMessageextendsAVIMTypedMessage{
publicStringgetText();
publicvoidsetText(Stringtext);
publicMap<String,Object>getAttrs();
publicvoidsetAttrs(Map<String,Object>attr); }