今天在慕课网学习了Android进阶课程推送的server端处理回执的消息

这集课程主要介绍了,当server往client推送消息的时候,client须要发送一个回执回来确认收到了推送消息才算一次完整的推送过程。

详细的实现方法为server推送一个消息到client的时候,会生成一个相应的uuid标识这个消息,并把这个消息以及uuid存储到数据库中。client收到消息后,取出当中的uuid并将这个uuid发给server端,服务端收到这个uuid。依据uuid到数据库里删除了相应的消息记录,整个推送算完毕。

这里先贴出比較核心的发送代码

public void sendNotifcationToUser(String apiKey, String username,
String title, String message, String uri) {
log.debug("sendNotifcationToUser()...");
Random random = new Random();
//这个id就是client发送回执相应的uuid
String id = Integer.toHexString(random.nextInt());
IQ notificationIQ = createNotificationIQ(id, apiKey, title, message, uri);
ClientSession session = sessionManager.getSession(username);
if (session != null) {
if (session.getPresence().isAvailable()) {
notificationIQ.setTo(session.getAddress());
session.deliver(notificationIQ);
}
else{
saveNotification(apiKey, username, title, message, uri, id);
}
}
//无论用户存在不存在都须要将消息存入数据库,直到用户收到消息发送回馈之后再删除
try {
User user = mUserService.getUserByUsername(username);
if(null != user){
saveNotification(apiKey, username, title, message, uri, id);
}
} catch (UserNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

能够看到,每次推送消息给client的时候都会做入库操作。

同一时候,源码里还有个业务逻辑,当server端检測到client从离线到上线状态的时候,会去数据库查找是否有该客户的的消息,有的话就会取出来发送,代码例如以下

List<Notification> list = mNotificationSevice.findNotificationByUsername(session.getUsername());
if(null != list && list.size() > 0){
for(Notification notification: list){
String apiKey = notification.getApiKey();
String title = notification.getTitle();
String message = notification.getMessage();
String uri = notification.getUri(); mNotificationManager.sendNotifcationToUser(apiKey, session.getUsername(), title, message, uri);
mNotificationSevice.deleteNotification(notification);
}
}

这个代码存在的一个bug是,当检測到有消息要给刚上线的client发送的时候。调用发送方法sendNotifcationToUser。并从数据库删除掉了原来的消息。这样操作后,会发如今sendNotifcationToUser里入库的消息被

mNotificationSevice.deleteNotification(notification);也一起删除了(当然原来的入库的消息也一起删除,但这个删除是正确的),而刚刚入库的那条消息是不应该删除的,必须等client发送回执回来后再删除。

视频作者郭神对这个bug的解决方法例如以下。先直接贴出代码

public void sendNotifcationToUser(String apiKey, String username,
String title, String message, String uri, boolean shouldSave) {
log.debug("sendNotifcationToUser()...");
Random random = new Random();
//这个id就是client发送回执相应的uuid
String id = Integer.toHexString(random.nextInt());
IQ notificationIQ = createNotificationIQ(id, apiKey, title, message, uri);
ClientSession session = sessionManager.getSession(username);
if (session != null) {
if (session.getPresence().isAvailable()) {
notificationIQ.setTo(session.getAddress());
session.deliver(notificationIQ);
}
else{
saveNotification(apiKey, username, title, message, uri, id);
}
}
//无论用户存在不存在都须要将消息存入数据库,直到用户收到消息发送回馈之后再删除
try {
User user = mUserService.getUserByUsername(username);
if(null != user && shouldSave){
saveNotification(apiKey, username, title, message, uri, id);
}
} catch (UserNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

以上代码添加了一个字段shouldSave来推断是否入库,同一时候在检測到client上线而且数据库有之前发送失败的消息得推送的时候,传入false

if(null != list && list.size() > 0){
for(Notification notification: list){
String apiKey = notification.getApiKey();
String title = notification.getTitle();
String message = notification.getMessage();
String uri = notification.getUri(); mNotificationManager.sendNotifcationToUser(apiKey, session.getUsername(), title, message, uri, false);
mNotificationSevice.deleteNotification(notification);
}
}

这样改完測了之后,发现没有不论什么问题,client从离线到上线后,原本存在数据库的消息都没有了,满足了需求。

可是。事实上是有问题的,当client从离线到上线而且server端从数据库检測到有消息得推送的时候,由于传入sendNotifcationToUser的最后一个參数是false,根本没有做入库操作。所以数据库根本没有这条发送消息的数据,client收到消息发送回执后,server没有相应的数据能够删除,导致看起来似乎达到了预期的效果。

针对这个问题。我做的改动例如以下,针对client从离线到在线的状态并须要推送之前为推送成功的消息,从数据库取出数据,直接推送该消息,不删除该消息。也不再插入新消息,等收到client回执后再删除。

public void sendNotifcationToUser(String id, String apiKey, String username,
String title, String message, String uri, boolean shouldSave) {
log.debug("sendNotifcationToUser()...");
IQ notificationIQ = createNotificationIQ(id, apiKey, title, message, uri);
ClientSession session = sessionManager.getSession(username);
if (session != null) {
if (session.getPresence().isAvailable()) {
notificationIQ.setTo(session.getAddress());
session.deliver(notificationIQ);
}
else if(shouldSave){
saveNotification(apiKey, username, title, message, uri, id);
}
}
//无论用户存在不存在都须要将消息存入数据库,直到用户收到消息发送回馈之后再删除
try {
User user = mUserService.getUserByUsername(username);
if(null != user && shouldSave){
saveNotification(apiKey, username, title, message, uri, id);
}
} catch (UserNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

这里还多了id字段,每次发送消息,id消息都是生成一个新的。对于发送之前的消息。全然不是必需生成新的id(即uuid),取出原来消息的id即可了,查找消息的地方改为例如以下

List<Notification> list = mNotificationSevice.findNotificationByUsername(session.getUsername());
if(null != list && list.size() > 0){
for(Notification notification: list){
String apiKey = notification.getApiKey();
String title = notification.getTitle();
String message = notification.getMessage();
String uri = notification.getUri();
String id = notification.getUuid();
mNotificationManager.sendNotifcationToUser(id, apiKey, session.getUsername(), title, message, uri, false);
}
}
这样就能够避免作者郭神的bug。事实上思路非常easy。就是又一次发送消息的时候不再入库消息,而是取出之前的消息来发送。等收到client回执后再删除。

Android推送进阶课程学习笔记的更多相关文章

  1. Android推送通知指南

      Android推送通知指南 在开发Android和iPhone应用程序时,我们往往需要从服务器不定的向手机客户端即时推送各种通知消息,iPhone上已经有了比较简单的和完美的推送通知解决方案,可是 ...

  2. Android推送方案

    一. 常见的推送原理: 1)轮询(Pull)方式:应用程序应当阶段性的与服务器进行连接并查询是否有新的消息到达,你必须自己实现与服务器之间的通信,例如消息排队等.而且你还要考虑轮询的频率,如果太慢可能 ...

  3. android推送方式

    本文介绍在Android中实现推送方式的基础知识及相关解决方案.推送功能在手机开发中应用的场景是越来起来了,不说别的,就我们手机上的新闻客户端就时不j时的推送过来新的消息,很方便的阅读最新的新闻信息. ...

  4. Android推送服务(1)几种实现方式

    1.几种常见的解决方案实现原理 1)轮询(Pull)方式:应用程序应当阶段性的与服务器进行连接并查询是否有新的消息到达,你必须自己实现与服务器之间的通信,例如消息排队等.而且你还要考虑轮询的频率,如果 ...

  5. JavaEE精英进阶课学习笔记《博学谷》

    JavaEE精英进阶课学习笔记<博学谷> 第1章 亿可控系统分析与设计 学习目标 了解物联网应用领域及发展现状 能够说出亿可控的核心功能 能够画出亿可控的系统架构图 能够完成亿可控环境的准 ...

  6. Mosquitto搭建Android推送服务(一)MQTT简介

    总体概要: MQTT系列文章分为4部分 1.MQTT简介 2.mosquitto服务器搭建 3.编写Mosquitto的可视化工具 4.使用Mosquitto完成Android推送服务 文章钢要: 对 ...

  7. Android 推送实现

    解决数据同步的问题:常用的方法有2种. (1) 定时去服务器上查询数据,也叫Polling. (2) 手机跟服务器之间维护一个 TCP 长连接,或者使用SMS,当服务器有数据时,实时推送到客户端,也就 ...

  8. Android推送技术研究

    前言 最近研究Android推送的实现, 研究了两天一夜, 有了一点收获, 写下来既为了分享, 也为了吐槽. 需要说明的是有些东西偏底层硬件和通信行业, 我对这些一窍不通, 只能说说自己的理解. 为什 ...

  9. Android推送分析

     cpu多核利用能够实现Android推送的吞吐量. 讲明白这点,我们需要了解Android推送的基本原理了.如果实现C(客户端)与server(客户端)实时通讯了.这里有两种思路了: 1.一种是定时 ...

随机推荐

  1. eclipse git冲突解决

    1.工程->Team->同步: 2.从远程pull至本地,就会出现如下内容: 3.使用Merge Tool,执行第二项 4.再手动修改 4.修改后的文件需要添加到Git index中去: ...

  2. spring @configuration使用

    http://yaobenzhang.blog.163.com/blog/static/2143951132014811105138824/

  3. 【MapReduce】经常使用计算模型具体解释

    前一阵子參加炼数成金的MapReduce培训,培训中的作业样例比較有代表性,用于解释问题再好只是了. 有一本国外的有关MR的教材,比較有用.点此下载. 一.MapReduce应用场景 MR能解决什么问 ...

  4. Objc执行时读取和写入plist文件遇到的问题

    以下是本猫保持游戏NPC和物件交互的plist文件: 随着游戏和玩家逐步发生互动,玩家会改动人物和物件的交互的状态.这也是RPG游戏最主要的功能. 在切换每一个地图时须要将上一个地图发生的改变存储到p ...

  5. Light OJ 1373 Strongly Connected Chemicals 二分匹配最大独立集

    m种阳离子 n种阴离子 然后一个m*n的矩阵 第i行第j列为1代表第i种阴离子和第j种阴离子相互吸引 0表示排斥 求在阳离子和阴离子都至少有一种的情况下 最多存在多少种离子能够共存 阴阳离子都至少须要 ...

  6. listview-属性大全

    <ListView <!-- 决定listview里的内容是否从底部开始 -- android:stackFromBottom="true" </Listview ...

  7. 2. Dubbo和Zookeeper的关系

    转自:https://www.cnblogs.com/hirampeng/p/9540243.html Dubbo建议使用Zookeeper作为服务的注册中心. 1.   Zookeeper的作用: ...

  8. Chome 浏览器,您的连接不是私密连接

    网上搜索了半天,最后才发现是去广告插件/软件的原因, 关掉广告插件/者软件,或者重新导入证书, 就可以了.

  9. Python数据结构同Json类型数据相互转换的用法

    在做Python接口自动化的时候,经常要用到Python数据结构同Json类型数据相互转换来供我们做进一步的验证提供数据,在此做个记录和总结 Python数据结构同Json类型数据相互转换的函数有:j ...

  10. hibernate 的映射文件快速生成:使用CodeSmith快速生成映射文件和映射类

    一 CodeSmith简介 本文以表自动生成NHibernate的映射文件和映射类的实例来说明一下本软件的使用方法. CodeSmith是一种基于模板的代码生成工具,其使用类似于ASP.NET的语法来 ...