基于Bmob的简单即时通讯
前言:
关于即时通讯,项目中要是需要一个收发消息的功能。从开始到写完即时通讯这块儿,花了大约3天时间。但真的想吐槽下bmobIM的服务器,有短板时间都在等待连接:disconnect
或者java.util.concurrent.TimeoutException
。问他们客服,他们说是IM的带宽满了。原话是这样:IM带宽满了。心里也是一万个无奈呀,但是也没办法,项目负责人点名了bmob,那就来吧:
集成:
bmob的文档这块儿写得算是不错了,我来整理一下:
- IM SDK使用Data SDK的BmobFile用于图片、语音等文件消息的发送,即特定的IM SDK只能和特定版本的Data SDK匹配。
IM SDK 版本 | Data SDK 版本 |
---|---|
bmob-im:2.0.1 至 2.0.2 | bmob-sdk:3.4.6-0304 |
bmob-im:2.0.3 至 2.0.4 | bmob-sdk:3.4.6 |
bmob-im:2.0.5 | bmob-sdk:3.4.7-aar |
bmob-im:2.0.6 至 2.0.8 | bmob-sdk:3.5.5 |
bmob-im:2.0.9 | bmob-sdk:3.5.6 |
bmob-im:2.1.1 | bmob-sdk:3.6.3 |
- 在project下面的build.gradle文件中添加maven仓库地址:
buildscript {repositories {jcenter()}dependencies {classpath 'com.android.tools.build:gradle:1.3.0'}
}allprojects {repositories {jcenter()//TODO 集成:1.1、配置Bmob的maven仓库地址maven { url "https://raw.github.com/bmob/bmob-android-sdk/master" }}
}task clean(type: Delete) {delete rootProject.buildDir
}
- 在app下的build.gradle文件中添加dependencies外部依赖:(此处注意Data和IM的SDK版本的对应关系)
dependencies {compile fileTree(dir: 'libs', include: ['*.jar'])//TODO 集成:1.2、配置IM SDK(bmob-im)版本和Data SDK(bmob-sdk)版本:特定版本的bmob-im依赖特定版本的bmob-sdkcompile 'cn.bmob.android:bmob-im:2.1.1@aar'compile 'cn.bmob.android:bmob-sdk:3.6.3'}
- 在AndroidManifest.xml下添加你的APP KEY:
<?xml version="1.0" encoding="utf-8"?>
<manifest ...//权限<application...<meta-dataandroid:name="Bmob_APP_KEY"android:value="fef642bee9678388a478d8b5b25bafa0" />...</application></manifest>
- 权限:
<!--TODO 1.4、配置IM SDK需要的权限--><!--网络权限 --><uses-permission android:name="android.permission.INTERNET" /><!-- 监听网络的变化 --><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /><!-- 设备休眠 --><uses-permission android:name="android.permission.WAKE_LOCK" /><uses-permission android:name="android.permission.READ_PHONE_STATE" /><!-- sd卡存储--><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><!--摄像头--><uses-permission android:name="android.permission.CAMERA" /><!--录音--><uses-permission android:name="android.permission.RECORD_AUDIO" /><!--通知震动--><uses-permission android:name="android.permission.VIBRATE" />
- 在AndroidManifest.xml下添加service、receiver标签:
<?xml version="1.0" encoding="utf-8"?>
<manifest ...//权限<application...<!--TODO 集成:1.5、配置IM SDK需要的广播和服务--><receiver android:name="cn.bmob.newim.core.ConnectChangeReceiver" ><intent-filter><action android:name="cn.bmob.action.RECONNECT" /><action android:name="android.net.conn.CONNECTIVITY_CHANGE" /><action android:name="android.intent.action.BOOT_COMPLETED" /><action android:name="android.intent.action.USER_PRESENT" /></intent-filter></receiver><serviceandroid:name="cn.bmob.newim.core.service.BmobIMService"android:process=":bmobcore" /><serviceandroid:name="cn.bmob.newim.core.service.NotifyService"android:process=":bmobcore" /><service android:name="cn.bmob.newim.core.service.ReConnectService" /><service android:name="cn.bmob.newim.core.service.HeartBeatService" />...</application></manifest>
项目的集成到这儿就结束了,剩下的就是如何使用这些东西了,简单看下我的流程图。
创建会话列表和好友列表(RecycleView)
- 首先说下个人认为官方文档中最难理解的一个名词:
会话
。会话分为暂态会话
和常态会话
。我对会话
的理解:就好比两个好友打电话时,要有一条连通的电话线一样,要实现IM,也要有连通双方的一根线,而这根线就相当于是会话
。应用在本地都会有数据表,用来存储应用中的数据。暂态会话不会保存在本地数据库中;常态会话会被保存到本地数据库中(暂态会话可以用来加好友,常态会话用来聊天)。 - 怪当时太年轻,以为即时通讯就只是聊天,在使用SDK完成加好友操作之后才看的IM文档,所以暂态会话这里就不说了,但是道理应该是相通的,相信看完常态会话之后,态会话都不是事儿。
- 即时通讯Demo中有两个RecycleView,一个用来存储好友列表,一个用来存储会话列表。而会话列表在你搞完发消息之前肯定是空的。
好友列表:(好友的添加就不说了,自行添加一些好友就行)
会话列表:(当然你的肯定是空的)
RecycleView点击事件-创建会话入口
首先看下官方的Demo:
adapter.setOnRecyclerViewListener(new OnRecyclerViewListener() {@Overridepublic void onItemClick(int position) {if (position == 0) {//跳转到新朋友页面startActivity(NewFriendActivity.class, null);} else {Friend friend = adapter.getItem(position);User user = friend.getFriendUser();BmobIMUserInfo info = new BmobIMUserInfo(user.getObjectId(), user.getUsername(), user.getAvatar());//TODO 会话:4.1、创建一个常态会话入口,好友聊天BmobIMConversation conversationEntrance = BmobIM.getInstance().startPrivateConversation(info, null);Bundle bundle = new Bundle();bundle.putSerializable("c", conversationEntrance);Intent intent = new Intent();intent.setClass(getActivity(), ChatActivity.class);if (bundle != null) {intent.putExtra(getActivity().getPackageName(), bundle);}getActivity().startActivity(intent);}}
由Demo可知,用BmobIMConversation来创建常态会话,传入参数(info,null)
- info:会话肯定要知道会话双方的信息,方便服务器转发消息。一方是自己,由
BmobUser.getCurrentUser()
即可得到自己的信息,自己的信息应该默认已经传进去了,不需要我们管;而另一方,也就是通信对方的信息,就需要info传入会话人口了,info为BmobIMUserInfo
类型,需传入(用户id,用户name,用户头像(Url)),其构造和函数:
public BmobIMUserInfo(String var1, String var2, String var3) {this.userId = var1;this.name = var2;this.avatar = var3;}
startPrivateConversation(info, null)
默认为创建常态会话,若要创建暂态会话,可BmobIMConversation conversationEntrance = BmobIM.getInstance().startPrivateConversation(info, true, null);
- Demo中后面代码意思就是把创建好的
conversationEntrance
传给会话界面,我的方法是:
BmobIMUserInfo info = new BmobIMUserInfo(list.get(i).getObjectId(), list.get(i).getNickName(), list.get(i).getPicture_head().getFileUrl());BmobIMConversation conversation = BmobIM.getInstance().startPrivateConversation(info, null);fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag("text_button_wodeqiuyou")).remove(fragmentManager.findFragmentByTag("text_button_wodeqiuyou")).add(R.id.fragment_container, FragmentIM.newInstance(list.get(i).getNickName(), list.get(i).getObjectId(), conversation), "im_Layout").commit();
意思就是在构造方法中传个参数conversationEntrance
即可,之后在发送消息时会用到。
- 我的构造函数:
public static FragmentIM newInstance(String name, String id, BmobIMConversation conversation) {FragmentIM fragmentIM = new FragmentIM();fragmentIM.name = name;fragmentIM.id = id;fragmentIM.conversation = conversation;return fragmentIM;
}
发送消息
- 在会话界面首先初始化会话管理员:
private BmobIMConversation mConversationManager;...@Nullable@Overridepublic View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_im, container, false);mConversationManager = BmobIMConversation.obtain(BmobIMClient.getInstance(), conversation);...return view;}
- 在这之后,就可以设置button的点击发送消息:
btn_chat_send.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String text = editText.getText().toString();//text即发送的消息if (BmobIM.getInstance().getCurrentStatus().getCode() != ConnectionStatus.CONNECTED.getCode()) {Toast.makeText(getContext(), "尚未连接IM服务器", Toast.LENGTH_SHORT).show();} else if (text.trim().equals("")) {Toast.makeText(getContext(), "请输入内容", Toast.LENGTH_SHORT).show();} else {final BmobIMTextMessage message = new BmobIMTextMessage();message.setContent(text);//可随意设置额外信息Map<String, Object> map = new HashMap<>();map.put("level", "1");message.setExtraMap(map);message.setExtra("OK");mConversationManager.sendMessage(message, listener);}}});
- 我的消息发送器:(如果打出Toast,那么说明发送成功)
/*** 消息发送监听器*/public MessageSendListener listener = new MessageSendListener() {@Overridepublic void onProgress(int value) {super.onProgress(value);//文件类型的消息才有进度值Log.e(TAG, "onProgress: " + value);}@Overridepublic void onStart(BmobIMMessage msg) {super.onStart(msg);chatAdapter.addMessage(msg);editText.setText("");scrollToBottom();}@Overridepublic void done(BmobIMMessage msg, BmobException e) {Toast.makeText(getContext(), "发送成功", Toast.LENGTH_SHORT).show();chatAdapter.notifyDataSetChanged();editText.setText("");scrollToBottom();if (e != null) {Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_SHORT).show();Log.e(TAG, "done: " + e.getMessage());}}};
接收消息
- 按照官方文档所说,创建全局消息接收器(个人建议创建全局消息接收器)
//TODO 集成:1.6、自定义消息接收器处理在线消息和离线消息
public class DemoMessageHandler extends BmobIMMessageHandler {@SuppressLint("SimpleDateFormat")SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");private static final String TAG = "DemoMessageHandler";@Overridepublic void onMessageReceive(final MessageEvent event) {//在线消息Log.e(TAG, "bindView: getFromId "+event.getMessage().getFromId() );Log.e(TAG, "bindView: getContent "+event.getMessage().getContent() );Log.e(TAG, "bindView: getExtra "+event.getMessage().getExtra() );Log.e(TAG, "bindView: getToId "+event.getMessage().getToId() );Log.e(TAG, "bindView: getCreateTime "+df.format(event.getMessage().getCreateTime()));Log.e(TAG, "bindView: getReceiveStatus "+event.getMessage().getReceiveStatus() );FragmentIM.chatAdapter.addMessage(event.getMessage());}@Overridepublic void onOfflineReceive(final OfflineMessageEvent event) {//离线消息,每次connect的时候会查询离线消息,如果有,此方法会被调用Map<String, List<MessageEvent>> map = event.getEventMap();//挨个检测下离线消息所属的用户的信息是否需要更新Toast.makeText(MainActivity.context, "有" + map.size() + "个用户发来离线消息", Toast.LENGTH_SHORT).show();for (Map.Entry<String, List<MessageEvent>> entry : map.entrySet()) {List<MessageEvent> list = entry.getValue();int size = list.size();Log.e(TAG, "onOfflineReceive: "+"用户" + entry.getKey() + "发来" + size + "条消息" );for (int i = 0; i < size; i++) {Log.e(TAG, "bindView: 离线消息: "+i+ " getFromId "+list.get(i).getMessage().getFromId() );Log.e(TAG, "bindView: 离线消息: "+i+ " getContent "+list.get(i).getMessage().getContent() );Log.e(TAG, "bindView: 离线消息: "+i+ " getExtra "+list.get(i).getMessage().getExtra() );Log.e(TAG, "bindView: 离线消息: "+i+ " getToId "+list.get(i).getMessage().getToId() );Log.e(TAG, "bindView: 离线消息: "+i+ " getCreateTime "+df.format(list.get(i).getMessage().getCreateTime()));Log.e(TAG, "bindView: 离线消息: "+i+ " getReceiveStatus "+list.get(i).getMessage().getReceiveStatus() );}}}
}
- 在消息界面也有个RecycleView:
- 我的Adapter的addMessage和addMessages方法:
public void addMessage(BmobIMMessage message) {messageList.addAll(Arrays.asList(message));notifyDataSetChanged();FragmentIM.scrollToBottom();//将RecycleView滑动到最低端}public void addMessages(List<BmobIMMessage> messages) {messageList.addAll(0, messages);notifyDataSetChanged();FragmentIM.scrollToBottom();//将RecycleView滑动到最低端}
- FragmentIM.scrollToBottom()方法:
public static void scrollToBottom() {layoutManager.scrollToPositionWithOffset(chatAdapter.getItemCount() - 1, 0);}
如此,一个简单的即时通讯Demo就完成了。
基于Bmob的简单即时通讯相关推荐
- bs模式Java web,基于BS模式的即时通讯系统的设计与实现(MyEclipse)
基于BS模式的即时通讯系统的设计与实现(MyEclipse)(包含选题审批表,任务书,开题报告,中期检查表,毕业论文13000字,答辩记录,成绩评定册,源程序) 摘 要:即时通讯(Instant M ...
- java xmpp协议_GitHub - zhengzhi530/xmpp: 基于Xmpp协议的即时通讯社交软件(客户端+服务端)...
yyquan 开源一个自己去年写的基于Xmpp协议的即时通讯社交软件 (客户端+服务端) 本项目仅供参考,对于正在学习Xmpp以及javaweb后台的同学,可以看一下. 做这个项目纯属个人兴趣爱好,所 ...
- 基于Linux下的即时通讯聊天室项目(全代码 有注释 可直接运行)
基于Linux下的即时通讯聊天室项目 一.序言 二.具体功能 三.系统客户要求 四.具体代码 1.服务器代码 2.客户端代码 一.序言 最近在写一个基于Linux下的聊天工具 它适合于局域网内所有人进 ...
- 基于Android开发的即时通讯聊天app
基于Android开发的即时通讯聊天app 前言 即时通讯(Instant Messaging,简称IM)在互联网中应用十分广泛,它可以和很多的领域结合,发挥十分重要的作用.比如金融行业的支付宝.各大 ...
- java 幻影_幻影(Phantom)消息平台,是一款基于Java实现的即时通讯(IM)系统
Phantom-Platform 介绍 幻影(Phantom)消息平台,是一款基于Java实现的即时通讯(IM)系统. 提供支持单聊.群聊.SDK等通用的技术通讯组件,开箱即用. 软件架构 构建 项目 ...
- 基于socket的可发送表情简单即时通讯
前言 这段时间做的东西比较杂,但是对学习来说还是很有帮助的,这次做的基于socket的即时通讯也是为了更加了解IM,本来是打算使用openfire或者apollo服务器来实现的,但是中途时间上的问题, ...
- 基于融云的即时通讯开发(一)
一.概述 现在的应用中,即时通讯功能已经很普遍了,从这篇文章开始,我们以第三方平台融云的服务为基础,研究一下如何开发一个具有及时通信功能的软件. 首先,进入融云的官网,地址如下: http://ron ...
- 基于websocket协议的即时通讯webapp(摘自本人毕业论文)
即时通讯实现 功能结构图 Spring WebSocket配置 本软件的即时通讯技术采用了WebSocket协议,因为从spring4.0的版本才开始支持WebSocket,所以本软件服务端的spri ...
- 基于B/S的即时通讯微博系统
技术:Java.JSP等 摘要: 随着信息时代的发展,人们对于网络社交的需求愈发强烈,互联网上也涌现出如新浪微博,贴吧留言贴,聊天室等一些成熟的应用软件.本微博系统使用 Java 语言进行开发,采用了 ...
最新文章
- mysql七:视图、触发器、事务、存储过程、函数
- 小团队 vs 大团队
- 关于python变量_关于python变量练习题
- 1220.统计元音字母序列的数目-LeetCode
- js中变量名提升和函数名提升
- HDU1872 稳定排序【稳定排序】
- svn 服务器修改密码,用户自行修改svn密码的简单服务
- Verilog入门教程与实例分享
- pmp学习资料下载-pmp备考
- 「架构师必备」java程序员面试宝典百度云
- 一个汉字到底占几个字节
- ExecuteNonQuery()的用法
- 【机器人栅格地图】基于蚁群优化遗传算法求解机器人栅格地图最短路径规划问题附Matlab源码
- 设置了监视哨的顺序查找算法效率高?你确定吗?
- 识别表格变成电子版的软件有什么?这些识别软件分享给你
- 71页全域旅游综合整体解决方案2021 ppt
- 希尔伯特变换与单边带调制
- 结对编程----五子棋游戏
- php 使用apache中的ab进行页面压力测试
- SleepBetter Privacy Policy