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