转载请标明出处: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

首先是用户第一次登录时候绑定的回调

  1. @Override
  2. public void onBind(final Context context, int errorCode, String appid,
  3. String userId, String channelId, String requestId)
  4. {
  5. String responseString = "onBind errorCode=" + errorCode + " appid="
  6. + appid + " userId=" + userId + " channelId=" + channelId
  7. + " requestId=" + requestId;
  8. Log.e(TAG, responseString);
  9. if (errorCode == 0)
  10. {
  11. SharePreferenceUtil util = PushApplication.getInstance()
  12. .getSpUtil();
  13. util.setAppId(appid);
  14. util.setChannelId(channelId);
  15. util.setUserId(userId);
  16. } else
  17. // 如果网络正常,则重试
  18. {
  19. if (NetUtil.isNetConnected(context))
  20. {
  21. T.showLong(context, "启动失败,正在重试...");
  22. new Handler().postDelayed(new Runnable()
  23. {
  24. @Override
  25. public void run()
  26. {
  27. PushManager.startWork(context,
  28. PushConstants.LOGIN_TYPE_API_KEY,
  29. PushApplication.API_KEY);
  30. }
  31. }, 2000);// 两秒后重新开始验证
  32. } else
  33. {
  34. T.showLong(context, R.string.net_error_tip);
  35. }
  36. }
  37. // 回调函数
  38. for (int i = 0; i < bindListeners.size(); i++)
  39. bindListeners.get(i).onBind(userId, errorCode);
  40. }

初次绑定的时候,如果绑定成功则使用SharedPreferences存储userId,channelId等数据

然后回调:bindListeners.get(i).onBind(userId, errorCode);给所有注册该事件的发出通知

下面看listener.onBind

  1. /**
  2. * 收到通知
  3. */
  4. @Override
  5. public void onBind(String userId, int errorCode)
  6. {
  7. Log.e("TAG", "Login Activity onBind ");
  8. if (errorCode == 0)
  9. {
  10. Log.e("TAG", "Login Activity onBind success ");
  11. // 如果绑定账号成功,由于第一次运行,给同一tag的人推送一条新人消息
  12. User u = new User(mSpUtil.getUserId(), mSpUtil.getChannelId(),
  13. mSpUtil.getNick(), mSpUtil.getHeadIcon(), 0);
  14. mUserDB.addUser(u);// 把自己添加到数据库
  15. Message firstSendMsg = new Message(System.currentTimeMillis(), "");
  16. firstSendMsg.setHello("hello");
  17. task = new SendMsgAsyncTask(mGson.toJson(firstSendMsg), "");
  18. task.setOnSendScuessListener(new OnSendScuessListener()
  19. {
  20. @Override
  21. public void sendScuess()
  22. {
  23. if (mLoadingDialog != null && mLoadingDialog.isVisible())
  24. mLoadingDialog.dismiss();
  25. mHandler.removeCallbacks(mConnTimeoutCallback);
  26. finish();
  27. Intent intent = new Intent(LoginActivity.this,
  28. MainActivity.class);
  29. startActivity(intent);
  30. }
  31. });
  32. task.send();
  33. }
  34. }

首先将自己保存到本地数据库,然后发送一个Message给所有的用户,设置一个特殊字段hello;也就是上述的原理分析中的部分~

2、onMessage

收到百度云推送的Receiver中的onMessage

  1. @Override
  2. public void onMessage(Context context, String message,
  3. String customContentString)
  4. {
  5. String messageString = "收到消息 message=\"" + message
  6. + "\" customContentString=" + customContentString;
  7. Log.e(TAG, messageString);
  8. Message receivedMsg = PushApplication.getInstance().getGson()
  9. .fromJson(message, Message.class);
  10. // 对接收到的消息进行处理
  11. parseMessage(receivedMsg);
  12. }
  13. /**
  14. * 消息:1、携带hello,表示新人加入,应该自动回复一个world 消息; 2、普通消息;
  15. *
  16. * @param msg
  17. */
  18. private void parseMessage(Message msg)
  19. {
  20. String userId = msg.getUserId();
  21. // 自己的消息
  22. if (userId
  23. .equals(PushApplication.getInstance().getSpUtil().getUserId()))
  24. return;
  25. if (checkHasNewFriend(msg) || checkAutoResponse(msg))
  26. return;
  27. // 普通消息
  28. UserDB userDB = PushApplication.getInstance().getUserDB();
  29. User user = userDB.selectInfo(userId);
  30. // 漏网之鱼
  31. if (user == null)
  32. {
  33. user = new User(userId, msg.getChannelId(), msg.getNickname(), 0, 0);
  34. userDB.addUser(user);
  35. // 通知监听的面板
  36. for (onNewFriendListener listener : friendListeners)
  37. listener.onNewFriend(user);
  38. }
  39. if (msgListeners.size() > 0)
  40. {// 有监听的时候,传递下去
  41. for (int i = 0; i < msgListeners.size(); i++)
  42. msgListeners.get(i).onNewMessage(msg);
  43. } else
  44. // 当前没有任何监听,即处理后台状态
  45. {
  46. // 将新来的消息进行存储
  47. ChatMessage chatMessage = new ChatMessage(msg.getMessage(), true,
  48. userId, msg.getHeadIcon(), msg.getNickname(), false,
  49. TimeUtil.getTime(msg.getTimeSamp()));
  50. PushApplication.getInstance().getMessageDB()
  51. .add(userId, chatMessage);
  52. showNotify(msg);
  53. }
  54. }
  55. /**
  56. * 检测是否是自动回复
  57. *
  58. * @param msg
  59. */
  60. private boolean checkAutoResponse(Message msg)
  61. {
  62. String world = msg.getWorld();
  63. String userId = msg.getUserId();
  64. if (!TextUtils.isEmpty(world))
  65. {
  66. User u = new User(userId, msg.getChannelId(), msg.getNickname(),
  67. msg.getHeadIcon(), 0);
  68. PushApplication.getInstance().getUserDB().addUser(u);// 存入或更新好友
  69. // 通知监听的面板
  70. for (onNewFriendListener listener : friendListeners)
  71. listener.onNewFriend(u);
  72. return true;
  73. }
  74. return false;
  75. }
  76. /**
  77. * 检测是否是新人加入
  78. *
  79. * @param msg
  80. */
  81. private boolean checkHasNewFriend(Message msg)
  82. {
  83. String userId = msg.getUserId();
  84. String hello = msg.getHello();
  85. // 新人发送的消息
  86. if (!TextUtils.isEmpty(hello))
  87. {
  88. Log.e("checkHasNewFriend", msg.getUserId());
  89. // 新人
  90. User u = new User(userId, msg.getChannelId(), msg.getNickname(),
  91. msg.getHeadIcon(), 0);
  92. PushApplication.getInstance().getUserDB().addUser(u);// 存入或更新好友
  93. T.showShort(PushApplication.getInstance(), u.getNick() + "加入");
  94. // 给新人回复一个应答
  95. Message message = new Message(System.currentTimeMillis(), "");
  96. message.setWorld("world");
  97. new SendMsgAsyncTask(PushApplication.getInstance().getGson()
  98. .toJson(message), userId);
  99. // 通知监听的面板
  100. for (onNewFriendListener listener : friendListeners)
  101. listener.onNewFriend(u);
  102. return true;
  103. }
  104. return false;
  105. }

当收到一个新的消息:

1、首先判断是不是自己发的,是,忽略;

2、判断是否携带hello字段,代表新人加入,携带,则保存到好友列表,且回复一个携带welcome字段的消息;

3、判断是否包含welcome字段,包含,存入好友列表

4、不是1、2、3则肯定是普通消息,将消息保存到本地数据库,然后为所有设置消息监听的发送回调即可~

MainTabFriends.java用户列表中收到新消息的回调:

  1. /**
  2. * 收到新消息时
  3. */
  4. @Override
  5. public void onNewMessage(Message message)
  6. {
  7. // 如果是自己发送的,则直接返回
  8. if (message.getUserId() == mSpUtils.getUserId())
  9. return;
  10. // 如果该用户已经有未读消息,更新未读消息的个数,并通知更新未读消息接口,最后notifyDataSetChanged
  11. String userId = message.getUserId();
  12. if (mUserMessages.containsKey(userId))
  13. {
  14. mUserMessages.put(userId, mUserMessages.get(userId) + 1);
  15. } else
  16. {
  17. mUserMessages.put(userId, 1);
  18. }
  19. mUnReadedMsgs++;
  20. notifyUnReadedMsg();
  21. // 将新来的消息进行存储
  22. ChatMessage chatMessage = new ChatMessage(message.getMessage(), true,
  23. userId, message.getHeadIcon(), message.getNickname(), false,
  24. TimeUtil.getTime(message.getTimeSamp()));
  25. mApplication.getMessageDB().add(userId, chatMessage);
  26. // 通知listview数据改变
  27. mAdapter.notifyDataSetChanged();
  28. }

1、如果是自己发的不做任何处理

2、如果当前消息发送用户已有未读消息,则更新该用户未读消息个数(用户Item上显示未读消息通知数),更新所有未读消息总和(朋友Tab上显示未读消息总和),然后存储该消息

3、刷新界面

ChattingActivity.java聊天界面的新消息回调

  1. @Override
  2. public void onNewMessage(Message message)
  3. {
  4. // 获得回复的消息
  5. if (mFromUser.getUserId().equals(message.getUserId()))
  6. {
  7. ChatMessage chatMessage = new ChatMessage();
  8. chatMessage.setComing(true);
  9. chatMessage.setDate(new Date(message.getTimeSamp()));
  10. chatMessage.setMessage(message.getMessage());
  11. chatMessage.setUserId(message.getUserId());
  12. chatMessage.setNickname(message.getNickname());
  13. chatMessage.setReaded(true);
  14. mDatas.add(chatMessage);
  15. mAdapter.notifyDataSetChanged();
  16. mChatMessagesListView.setSelection(mDatas.size() - 1);
  17. // 存入数据库,当前聊天记录
  18. mApplication.getMessageDB().add(mFromUser.getUserId(), chatMessage);
  19. }
  20. }

首先判断是否是正在聊天的用户发的消息,如果是,直接存入数据库,刷新聊天界面;

好了,细节也不展开描述了,大家自己看源码,bug肯定有,发现bug可以直接留言,方便其他学习的童鞋,也方便我了,多谢~~~~~~~~~~~~~~

ps:最近状态不好,我要去喝脉动~~~~

源码点击下载 大家可以先安装压缩文件里面的apk测试下,这样就可以发现别的伙伴了~~~

Android 高仿微信实时聊天 基于百度云推送的更多相关文章

  1. Android 高仿微信即时聊天 百度云为基础的推

    转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:[张鸿洋的博客] 一直在仿微信界面,今天最终有幸利用百 ...

  2. Android 高仿微信语音聊天页面高斯模糊效果

    目前的应用市场上,使用毛玻璃效果的APP随处可见,比如用过微信语音聊天的人可以发现,语音聊天页面就使用了高斯模糊效果. 先看下效果图: 仔细观察上图,我们可以发现,背景图以用户头像为模板,对其进行了高 ...

  3. Android推送服务——百度云推送

    一.推送服务简介 消息推送,顾名思义,是由一方主动发起,而另一方与发起方以某一种方式建立连接并接收消息.在Android开发中,这里的发起方我们把它叫做推送服务器(Push Server),接收方叫做 ...

  4. android开发(25) - 推送的实现,使用百度云推送

    什么叫推送? 中文名称:推送 英文名称:push 定义:描述因特网内容提供者和因特网用户之间工作方式的术语.“推送”指因特网内容提供者定期向预订用户“提供”数据. 项目中有可能会用到推送.如果自己写一 ...

  5. Android推送 百度云推送 入门篇

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/27231237 现在app基本都有推送的功能,于是看了下百度云的推送,官方文档和D ...

  6. 消息推送之百度云推送Android集成与使用方法

    这两天由于项目需要,研究了一下百度云推送,本来这事没什么多大工作量的,但注册百度开发者账户创建应用令我蛋疼菊紧了好一阵,这些东西做了对技术没啥提升,不做又不行,必经之路.好在我耗费了N多个毫毫秒秒后稀 ...

  7. 消息推送之百度云推送Android集成与用法

    这两天因为项目须要.研究了一下百度云推送,本来这事没什么多大工作量的,但注冊百度开发人员账户创建应用令我蛋疼菊紧了好一阵,这些东西做了对技术没啥提升,不做又不行,必经之路. 好在我耗费了N多个毫毫秒秒 ...

  8. ecmobile实现支付宝支付和百度云推送遇到的问题及解决方案(android)

    1.首先检测支付账户是否开通快捷支付服务,如果开通后,那么公钥是否上传(支付宝问题一定要找支付宝客服解决,找其他人没有用,支付宝客服可以帮你分析底层原因) 2.修改app配置文件:alipay_cal ...

  9. Amazon SNS移动推送更新——新增百度云推送和Windows平台支持

    Amazon SNS(Simple Notification Service)是一种基于云平台的消息通知和推送服务. SNS提供简单的 Web 服务接口和基于浏览器的管理控制台让用户可以简易设置.执行 ...

随机推荐

  1. getJSON回调函数不执行问题?

    利用getJSON异步请求时,回调函数不执行,不知道是什么问题? php 返回数据 header("Content-type:text/json"); echo json_enco ...

  2. ubuntu下配置protobuf

    http://blog.csdn.net/guoyilongedu/article/details/17093811 最近想研究protobuf ,尝试了很多次都没有成功,我用的是ubuntu,在虚拟 ...

  3. Qt for Mac:发布程序(widgets和quick2)

    当你用Qt开发好程序后,是不是会很期待将你的成果分享给你的小伙伴 可是Qt的库并不是OS X标配的,所以我们要自己去复制库到app包里,才可以让app在其他未安装Qt的电脑上运行. 比较幸运的是,Qt ...

  4. Java工程转换为Maven工程

    1. 前言 在开发中经常要建立一个Maven的子工程,对于没有模板的同学来说从Java工程来转换也是一个不错的选择.本文就如何从一个Java工程创建一个Maven工程做了一个介绍,相信对于将一个Jav ...

  5. android-wear开发之定义布局

    Android Wear使用跟手机一样的布局技术,但需要对特定情况进行设计.不要把手机的UI直接照搬过来.更多可查看:Android Wear Design Guidelines 当创建android ...

  6. jquery 插件JTable使用

    http://www.jtable.org/ 下载后增加: Add these lines to the HEAD section of your HTML document: <!-- Inc ...

  7. bzoj3192

    把堆顶和堆顶接起来,然后用树状数组模拟即可不得不说一开始我竟然把100000*100000当成不超出longint 而忘开int64,无药可救…… ..] of longint; now,n1,n2, ...

  8. weblogic启动报错之建域时未指定AdminServer的监听IP的引起的子节点启动故障

    各子节点不能启动,查看日志,报错如下: Unable to establish JMX Connectivity with the Adminstration Server AdminServer a ...

  9. 数据结构,可并堆(左偏树):COGS [APIO2012] 派遣

    796. [APIO2012] 派遣 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.  在这个帮派里,有一名忍者被称之为Master.除了Master以外,每名忍者都有且 ...

  10. 图论 BZOJ 3669 [Noi2014]魔法森林

    Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节 ...