Android 高仿微信实时聊天 基于百度云推送
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:【张鸿洋的博客】
一直在仿微信界面,今天终于有幸利用百度云推送仿一仿微信聊天了~~~
首先特别感谢:weidi1989分享的Android之基于百度云推送IM ,大家可以直接下载;省了很多事哈,本例中也使用了weidi的部分代码,凡是@author way的就是weidi1989的代码~~
1、效果图
核心功能也就上面的两张图了~~~我拿着手机和模拟器聊天,同时感谢群里的兄弟姐妹帮忙测试(好友列表中)。
2、原理
下面通过几个问题来说明下实现的原理:
1、如何实现给某个用户发送消息呢?
其实就是利用百度云提供的REST API,直接通过发送Http请求的形式给某个用户推送一条消息;
网址:http://developer.baidu.com/wiki/index.php?title=docs/cplat/push/api/list
实例:
push_msg
功能
推送消息,该接口可用于推送单个人、一群人、所有人以及固定设备的使用场景。
HTTP请求方式
POST
URL
http[s]://channel.api.duapp.com/rest/2.0/channel/channel
....
2、的确可以实现给某个用户或者一群用户推送消息,那么用户的昵称神马的咋获取的呢,我印象中百度云中没法存这样的数据?
嗯,其实用了一个比较巧妙的方式;在用户首次安装软件的时候,会要求用户填写注册信息,也就是昵称等;当用户填写完毕时,点击登录的时候:
1、发送一条比较特殊的消息,比如这个消息携带一个hello的字段,广播给所有用户;
2、其他用户在收到消息时,首先判断hello这个字段是否有值,有值则说明新用户加入,把该新用户存入本地数据库,然后更新用户列表;
3、其他用户给这个新用户回一条消息,附带一个特殊字段,比如welcome,当新用户收到携带welcome字段的消息时,表明这是对新用户hello的答复,然后将已存在用户添加到该新用户的用户列表。
基本原理就这样了,大家甚至可以利用上述的原理添加一些删除好友的功能;比如当用户点击删除好友,则发送一条特殊消息给被删除的对象,然后对方收到该消息,也将发送发删除。
相信大家在了解原理之后,这个例子瞬间从高大尚变成矮矬穷了,这尼玛,so easy,谁不会啊~~~
3、核心代码解析
由于代码量还是相当大的,也不想拆成几篇博客,所以准备将核心代码进行讲解下,其他的大家自己看源码~
关于这个例子的主界面,可以参考: 高仿微信5.2.1主界面架构 包含消息通知
关于百度云推送的入门,可以参考:Android推送 百度云推送 入门篇
好了,最主要就是收到百度云推送的Receiver
1、onBind
首先是用户第一次登录时候绑定的回调
- @Override
- public void onBind(final Context context, int errorCode, String appid,
- String userId, String channelId, String requestId)
- {
- String responseString = "onBind errorCode=" + errorCode + " appid="
- + appid + " userId=" + userId + " channelId=" + channelId
- + " requestId=" + requestId;
- Log.e(TAG, responseString);
- if (errorCode == 0)
- {
- SharePreferenceUtil util = PushApplication.getInstance()
- .getSpUtil();
- util.setAppId(appid);
- util.setChannelId(channelId);
- util.setUserId(userId);
- } else
- // 如果网络正常,则重试
- {
- if (NetUtil.isNetConnected(context))
- {
- T.showLong(context, "启动失败,正在重试...");
- new Handler().postDelayed(new Runnable()
- {
- @Override
- public void run()
- {
- PushManager.startWork(context,
- PushConstants.LOGIN_TYPE_API_KEY,
- PushApplication.API_KEY);
- }
- }, 2000);// 两秒后重新开始验证
- } else
- {
- T.showLong(context, R.string.net_error_tip);
- }
- }
- // 回调函数
- for (int i = 0; i < bindListeners.size(); i++)
- bindListeners.get(i).onBind(userId, errorCode);
- }
初次绑定的时候,如果绑定成功则使用SharedPreferences存储userId,channelId等数据
然后回调:bindListeners.get(i).onBind(userId, errorCode);给所有注册该事件的发出通知
下面看listener.onBind
- /**
- * 收到通知
- */
- @Override
- public void onBind(String userId, int errorCode)
- {
- Log.e("TAG", "Login Activity onBind ");
- if (errorCode == 0)
- {
- Log.e("TAG", "Login Activity onBind success ");
- // 如果绑定账号成功,由于第一次运行,给同一tag的人推送一条新人消息
- User u = new User(mSpUtil.getUserId(), mSpUtil.getChannelId(),
- mSpUtil.getNick(), mSpUtil.getHeadIcon(), 0);
- mUserDB.addUser(u);// 把自己添加到数据库
- Message firstSendMsg = new Message(System.currentTimeMillis(), "");
- firstSendMsg.setHello("hello");
- task = new SendMsgAsyncTask(mGson.toJson(firstSendMsg), "");
- task.setOnSendScuessListener(new OnSendScuessListener()
- {
- @Override
- public void sendScuess()
- {
- if (mLoadingDialog != null && mLoadingDialog.isVisible())
- mLoadingDialog.dismiss();
- mHandler.removeCallbacks(mConnTimeoutCallback);
- finish();
- Intent intent = new Intent(LoginActivity.this,
- MainActivity.class);
- startActivity(intent);
- }
- });
- task.send();
- }
- }
首先将自己保存到本地数据库,然后发送一个Message给所有的用户,设置一个特殊字段hello;也就是上述的原理分析中的部分~
2、onMessage
收到百度云推送的Receiver中的onMessage
- @Override
- public void onMessage(Context context, String message,
- String customContentString)
- {
- String messageString = "收到消息 message=\"" + message
- + "\" customContentString=" + customContentString;
- Log.e(TAG, messageString);
- Message receivedMsg = PushApplication.getInstance().getGson()
- .fromJson(message, Message.class);
- // 对接收到的消息进行处理
- parseMessage(receivedMsg);
- }
- /**
- * 消息:1、携带hello,表示新人加入,应该自动回复一个world 消息; 2、普通消息;
- *
- * @param msg
- */
- private void parseMessage(Message msg)
- {
- String userId = msg.getUserId();
- // 自己的消息
- if (userId
- .equals(PushApplication.getInstance().getSpUtil().getUserId()))
- return;
- if (checkHasNewFriend(msg) || checkAutoResponse(msg))
- return;
- // 普通消息
- UserDB userDB = PushApplication.getInstance().getUserDB();
- User user = userDB.selectInfo(userId);
- // 漏网之鱼
- if (user == null)
- {
- user = new User(userId, msg.getChannelId(), msg.getNickname(), 0, 0);
- userDB.addUser(user);
- // 通知监听的面板
- for (onNewFriendListener listener : friendListeners)
- listener.onNewFriend(user);
- }
- if (msgListeners.size() > 0)
- {// 有监听的时候,传递下去
- for (int i = 0; i < msgListeners.size(); i++)
- msgListeners.get(i).onNewMessage(msg);
- } else
- // 当前没有任何监听,即处理后台状态
- {
- // 将新来的消息进行存储
- ChatMessage chatMessage = new ChatMessage(msg.getMessage(), true,
- userId, msg.getHeadIcon(), msg.getNickname(), false,
- TimeUtil.getTime(msg.getTimeSamp()));
- PushApplication.getInstance().getMessageDB()
- .add(userId, chatMessage);
- showNotify(msg);
- }
- }
- /**
- * 检测是否是自动回复
- *
- * @param msg
- */
- private boolean checkAutoResponse(Message msg)
- {
- String world = msg.getWorld();
- String userId = msg.getUserId();
- if (!TextUtils.isEmpty(world))
- {
- User u = new User(userId, msg.getChannelId(), msg.getNickname(),
- msg.getHeadIcon(), 0);
- PushApplication.getInstance().getUserDB().addUser(u);// 存入或更新好友
- // 通知监听的面板
- for (onNewFriendListener listener : friendListeners)
- listener.onNewFriend(u);
- return true;
- }
- return false;
- }
- /**
- * 检测是否是新人加入
- *
- * @param msg
- */
- private boolean checkHasNewFriend(Message msg)
- {
- String userId = msg.getUserId();
- String hello = msg.getHello();
- // 新人发送的消息
- if (!TextUtils.isEmpty(hello))
- {
- Log.e("checkHasNewFriend", msg.getUserId());
- // 新人
- User u = new User(userId, msg.getChannelId(), msg.getNickname(),
- msg.getHeadIcon(), 0);
- PushApplication.getInstance().getUserDB().addUser(u);// 存入或更新好友
- T.showShort(PushApplication.getInstance(), u.getNick() + "加入");
- // 给新人回复一个应答
- Message message = new Message(System.currentTimeMillis(), "");
- message.setWorld("world");
- new SendMsgAsyncTask(PushApplication.getInstance().getGson()
- .toJson(message), userId);
- // 通知监听的面板
- for (onNewFriendListener listener : friendListeners)
- listener.onNewFriend(u);
- return true;
- }
- return false;
- }
当收到一个新的消息:
1、首先判断是不是自己发的,是,忽略;
2、判断是否携带hello字段,代表新人加入,携带,则保存到好友列表,且回复一个携带welcome字段的消息;
3、判断是否包含welcome字段,包含,存入好友列表
4、不是1、2、3则肯定是普通消息,将消息保存到本地数据库,然后为所有设置消息监听的发送回调即可~
MainTabFriends.java用户列表中收到新消息的回调:
- /**
- * 收到新消息时
- */
- @Override
- public void onNewMessage(Message message)
- {
- // 如果是自己发送的,则直接返回
- if (message.getUserId() == mSpUtils.getUserId())
- return;
- // 如果该用户已经有未读消息,更新未读消息的个数,并通知更新未读消息接口,最后notifyDataSetChanged
- String userId = message.getUserId();
- if (mUserMessages.containsKey(userId))
- {
- mUserMessages.put(userId, mUserMessages.get(userId) + 1);
- } else
- {
- mUserMessages.put(userId, 1);
- }
- mUnReadedMsgs++;
- notifyUnReadedMsg();
- // 将新来的消息进行存储
- ChatMessage chatMessage = new ChatMessage(message.getMessage(), true,
- userId, message.getHeadIcon(), message.getNickname(), false,
- TimeUtil.getTime(message.getTimeSamp()));
- mApplication.getMessageDB().add(userId, chatMessage);
- // 通知listview数据改变
- mAdapter.notifyDataSetChanged();
- }
1、如果是自己发的不做任何处理
2、如果当前消息发送用户已有未读消息,则更新该用户未读消息个数(用户Item上显示未读消息通知数),更新所有未读消息总和(朋友Tab上显示未读消息总和),然后存储该消息
3、刷新界面
ChattingActivity.java聊天界面的新消息回调
- @Override
- public void onNewMessage(Message message)
- {
- // 获得回复的消息
- if (mFromUser.getUserId().equals(message.getUserId()))
- {
- ChatMessage chatMessage = new ChatMessage();
- chatMessage.setComing(true);
- chatMessage.setDate(new Date(message.getTimeSamp()));
- chatMessage.setMessage(message.getMessage());
- chatMessage.setUserId(message.getUserId());
- chatMessage.setNickname(message.getNickname());
- chatMessage.setReaded(true);
- mDatas.add(chatMessage);
- mAdapter.notifyDataSetChanged();
- mChatMessagesListView.setSelection(mDatas.size() - 1);
- // 存入数据库,当前聊天记录
- mApplication.getMessageDB().add(mFromUser.getUserId(), chatMessage);
- }
- }
首先判断是否是正在聊天的用户发的消息,如果是,直接存入数据库,刷新聊天界面;
好了,细节也不展开描述了,大家自己看源码,bug肯定有,发现bug可以直接留言,方便其他学习的童鞋,也方便我了,多谢~~~~~~~~~~~~~~
ps:最近状态不好,我要去喝脉动~~~~
源码点击下载 大家可以先安装压缩文件里面的apk测试下,这样就可以发现别的伙伴了~~~
Android 高仿微信实时聊天 基于百度云推送的更多相关文章
- Android 高仿微信即时聊天 百度云为基础的推
转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:[张鸿洋的博客] 一直在仿微信界面,今天最终有幸利用百 ...
- Android 高仿微信语音聊天页面高斯模糊效果
目前的应用市场上,使用毛玻璃效果的APP随处可见,比如用过微信语音聊天的人可以发现,语音聊天页面就使用了高斯模糊效果. 先看下效果图: 仔细观察上图,我们可以发现,背景图以用户头像为模板,对其进行了高 ...
- Android推送服务——百度云推送
一.推送服务简介 消息推送,顾名思义,是由一方主动发起,而另一方与发起方以某一种方式建立连接并接收消息.在Android开发中,这里的发起方我们把它叫做推送服务器(Push Server),接收方叫做 ...
- android开发(25) - 推送的实现,使用百度云推送
什么叫推送? 中文名称:推送 英文名称:push 定义:描述因特网内容提供者和因特网用户之间工作方式的术语.“推送”指因特网内容提供者定期向预订用户“提供”数据. 项目中有可能会用到推送.如果自己写一 ...
- Android推送 百度云推送 入门篇
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/27231237 现在app基本都有推送的功能,于是看了下百度云的推送,官方文档和D ...
- 消息推送之百度云推送Android集成与使用方法
这两天由于项目需要,研究了一下百度云推送,本来这事没什么多大工作量的,但注册百度开发者账户创建应用令我蛋疼菊紧了好一阵,这些东西做了对技术没啥提升,不做又不行,必经之路.好在我耗费了N多个毫毫秒秒后稀 ...
- 消息推送之百度云推送Android集成与用法
这两天因为项目须要.研究了一下百度云推送,本来这事没什么多大工作量的,但注冊百度开发人员账户创建应用令我蛋疼菊紧了好一阵,这些东西做了对技术没啥提升,不做又不行,必经之路. 好在我耗费了N多个毫毫秒秒 ...
- ecmobile实现支付宝支付和百度云推送遇到的问题及解决方案(android)
1.首先检测支付账户是否开通快捷支付服务,如果开通后,那么公钥是否上传(支付宝问题一定要找支付宝客服解决,找其他人没有用,支付宝客服可以帮你分析底层原因) 2.修改app配置文件:alipay_cal ...
- Amazon SNS移动推送更新——新增百度云推送和Windows平台支持
Amazon SNS(Simple Notification Service)是一种基于云平台的消息通知和推送服务. SNS提供简单的 Web 服务接口和基于浏览器的管理控制台让用户可以简易设置.执行 ...
随机推荐
- 使用PHP预定义变量得到url地址及相关参数
获取url地址栏参数多种方法:$_SERVER["SERVER_PORT"]//获取端口$_SERVER['HTTP_HOST']//获取域名或主机地址 如www.sina.com ...
- YII 小部件 yii小部件查看方法 小物件做的表单
要使用小部件,可以先到总文件去找 framework/yiilite文件里面搜索“CAtiveForm” (如果觉得小部件的radio布局有点难看,可以在外面定义,具体可以在控制器里面定义) 如下 ...
- [r]Setting up Django and your web server with uWSGI and nginx
Setting up Django and your web server with uWSGI and nginx This tutorial is aimed at the Django user ...
- 【转】常见 jar包详解
转载自:http://www.cnblogs.com/xusir/archive/2013/05/19/3086878.html jar包 用途 axis.jar SOAP引擎包 commons- ...
- Unity3d 项目管理 版本管理
Unity3d中项目管理 版本管理 如果在提交文件的时候发现提示有"先更新,再提交的"提示的时候,这是因为,A提交了一个版本文件,版本是13,那么你还在修改版本为12的文件 ...
- Highways poj 2485
Description The island nation of Flatopia is perfectly flat. Unfortunately, Flatopia has no public h ...
- 一点BPXA的思考
懂的人自然懂... BPXA功能配置 这个概念现在还有印象,记录下来: 一,BPXA是用于BP使用第三方资源的.如使用ORACLE数据库,就是在XA里配置.它的特征是以<xa>开头 二,B ...
- IHS怎么通过80端口连接WAS——<转>
IHS如何通过80端口连接WAS? 经常看到有朋友问这个问题,所以简单总结一下基本步骤: IHS和WAS之间是通过Plugin来实现的,一般的Plugins和IHS安装在同一物理机器上,WAS安装 ...
- 一篇故事讲述了计算机网络里的基本概念:网关,DHCP,IP寻址,ARP欺骗,路由,DDOS等...
计算机主机网关的作用是什么? 假设你的名字叫小不点,你住在一个大院子里,你的邻居有很多小伙伴,在门口传达室还有个看大门的李大爷,李大爷就是你的网关.当你想跟院子里的某个小伙伴玩,只要你在院子里大喊一声 ...
- java学习面向对象之this
在我们讲构造函数的时候,我们知道,如果同时在java的堆内存当中,同时存在好几个刚进内存,但是又没来得及初始化的同一个类的对象.在这种情况下,那么如何去区分栈内存当中的构造函数是属于那个对象的呢,其实 ...