android 实现mqtt消息推送,以及不停断线重连的问题解决
前段时间项目用到mqtt的消息推送,整理一下代码,代码的原型是网上找的,具体哪个地址已经忘记了。
代码的实现是新建了一个MyMqttService,全部功能都在里面实现,包括连服务器,断线重连,订阅消息,处理消息,发布消息等基本操作。
首先添加依赖:
dependencies {
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
}
然后编辑AndroidManifest.xml,先添加权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
再注册service:
<service android:name="org.eclipse.paho.android.service.MqttService" />
<service
android:name=".service.MyMqttService"
android:enabled="true"
android:exported="true"/>
接着进入正文MyMqttService.java,功能见注释吧:
package com.example.nan.mqtt.service;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.DisconnectedBufferOptions;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.json.JSONObject;
/**
* @author nan
*/
public class MyMqttService extends Service {
private static final String TAG = "nlgMqttService";
private static final String TOPIC_TO_QA = "/s2c/task_quality/";
private static final String publishTopic = "exampleAndroidPublishTopic";
private MqttAndroidClient mqttAndroidClient;
private NotificationManager mNotificationManager;
public MyMqttService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "MqttService onCreate executed");
//mqtt服务器的地址
final String serverUri = "tcp://192.168.10.10:1883";
//新建Client,以设备ID作为client ID
mqttAndroidClient = new MqttAndroidClient(MyMqttService.this, serverUri, getIMEI());
mqttAndroidClient.setCallback(new MqttCallbackExtended() {
@Override
public void connectComplete(boolean reconnect, String serverURI) {
//连接成功
if (reconnect) {
Log.d(TAG, "connectComplete: " + serverURI);
// Because Clean Session is true, we need to re-subscribe
subscribeAllTopics();
} else {
Log.d(TAG, "connectComplete: " + serverURI);
}
}
@Override
public void connectionLost(Throwable cause) {
//连接断开
Log.d(TAG, "connectionLost: connection was lost");
}
@Override
public void messageArrived(String topic, MqttMessage message) {
//订阅的消息送达,推送notify
String payload = new String(message.getPayload());
Log.d(TAG, "Topic: " + topic + " ==> Payload: " + payload);
if(mNotificationManager == null) {
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
int roleId = SinSimApp.getApp().getRole();
Gson gson = new Gson();
ServerToClientMsg msg = gson.fromJson(payload, new TypeToken<ServerToClientMsg>(){}.getType());
if(msg != null) {
//接受消息
if(topic != null) {
if(topic.equals(TOPIC_TO_QA)) {
Intent intent = new Intent(MyMqttService.this, ProcessToCheckoutActivity.class);
PendingIntent pi = PendingIntent.getActivity(MyMqttService.this, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(MyMqttService.this, TOPIC_TO_QA);
Notification notify = builder.setSmallIcon(R.mipmap.to_quality)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.to_quality))
.setDefaults(Notification.DEFAULT_SOUND|Notification.DEFAULT_VIBRATE)//响铃震动
.setContentTitle("快递来了")
.setAutoCancel(true)
.setContentIntent(pi)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setContentText("你的快递单号:" + msg.getOrderNum())
//不设置此项不会悬挂,false 不会出现悬挂
.build();
mNotificationManager.notify(2,notify);
}
}
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
//即服务器成功delivery消息
}
});
//新建连接设置
MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
//断开后,是否自动连接
mqttConnectOptions.setAutomaticReconnect(true);
//是否清空客户端的连接记录。若为true,则断开后,broker将自动清除该客户端连接信息
mqttConnectOptions.setCleanSession(false);
//设置超时时间,单位为秒
//mqttConnectOptions.setConnectionTimeout(2);
//心跳时间,单位为秒。即多长时间确认一次Client端是否在线
//mqttConnectOptions.setKeepAliveInterval(2);
//允许同时发送几条消息(未收到broker确认信息)
//mqttConnectOptions.setMaxInflight(10);
//选择MQTT版本
mqttConnectOptions.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
try {
Log.d(TAG, "onCreate: Connecting to " + serverUri);
//开始连接
mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.d(TAG, "onSuccess: Success to connect to " + serverUri);
DisconnectedBufferOptions disconnectedBufferOptions = new DisconnectedBufferOptions();
disconnectedBufferOptions.setBufferEnabled(true);
disconnectedBufferOptions.setBufferSize(100);
disconnectedBufferOptions.setPersistBuffer(false);
disconnectedBufferOptions.setDeleteOldestMessages(false);
mqttAndroidClient.setBufferOpts(disconnectedBufferOptions);
//成功连接以后开始订阅
subscribeAllTopics();
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
//连接失败
Log.d(TAG, "onFailure: Failed to connect to " + serverUri);
exception.printStackTrace();
}
});
} catch (MqttException ex) {
ex.printStackTrace();
}
//service绑定notification
Intent intent = new Intent(this, SplashActivity.class);
intent.putExtra(SinSimApp.FROM_NOTIFICATION, true);
//这边设置“FLAG_UPDATE_CURRENT”是为了让后面的Activity接收pendingIntent中Extra的数据
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("mqtt快递")
.setContentText("mqtt快递管理系统")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setContentIntent(pi)
.build();
startForeground(1, notification);
}
//订阅所有消息
private void subscribeAllTopics() {
subscribeToTopic(TOPIC_TO_QA);
}
/**
* 订阅消息
*/
public void subscribeToTopic(String subscriptionTopic) {
try {
mqttAndroidClient.subscribe(subscriptionTopic, 2, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.d(TAG, "onSuccess: Success to Subscribed!");
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.d(TAG, "onFailure: Failed to subscribe");
}
});
} catch (MqttException ex) {
Log.d(TAG, "subscribeToTopic: Exception whilst subscribing");
ex.printStackTrace();
}
}
/**
* 发布消息
*/
public void publishMessage(String msg) {
try {
MqttMessage message = new MqttMessage();
message.setPayload(msg.getBytes());
mqttAndroidClient.publish(publishTopic, message);
Log.d(TAG, "publishMessage: Message Published: " + msg);
} catch (MqttException e) {
Log.d(TAG, "publishMessage: Error Publishing: " + e.getMessage());
e.printStackTrace();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "MqttService onStartCommand executed");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
try {
if(mqttAndroidClient!=null){
//服务退出时client断开连接
mqttAndroidClient.disconnect();
}
} catch (MqttException e) {
e.printStackTrace();
}
Log.d(TAG, "MqttService onDestroy executed");
}
}
调试过程中出现过一个小插曲:服务在有些时候会不停的断线重连。断线重连的设置是开了的:
mqttConnectOptions.setAutomaticReconnect(true);
但是断开的原因找不到,当时还没有重写onDestory方法,就算退出应用也还在重连,一度怀疑service的开启与关闭的问题,还系统的重新学习了一下service的使用,学完以后也没有啥进展,然后重学mqtt的调用流程发挥了效果,在onDestory里面调用了disconnect()方法,完了以后在退出应用以后就不会重连了,但是重新开还是继续不停重连。到了晚上,奇怪的事情发生了,当夜深人静,独自加班的时候,居然再也复现不了了。为什么呢,心想可能平时给八阿哥上的香起了效果,那就开心的回家吧。下班的路上虽然开心的吃了块鸡排,但心里的结还是没有打开,为什么呢,是道德的沦丧还是人性的扭曲,让我独自加班还不饿给我复现问题。突然灵光一现,想到今天特么加班就我一个人,也就是一个人玩就是好的,玩的人多就会有问题,那么答案就来了,跟唯一性有关的只有clientID了,特么老子把clientID设置成用户id了,测试用的用户id就注册了3个,好几个人来回切着用,不出问题才怪。于是我默默的把clientID改成了设备id,困扰2天的问题就这么解决了。
---------------------
作者:邦德总管
来源:CSDN
原文:https://blog.csdn.net/a5nan/article/details/79975488
版权声明:本文为博主原创文章,转载请附上博文链接!
android 实现mqtt消息推送,以及不停断线重连的问题解决的更多相关文章
- android系统下消息推送机制
一.推送方式简介: 当前随着移动互联网的不断加速,消息推送的功能越来越普遍,不仅仅是应用在邮件推送上了,更多的体现在手机的APP上.当我们开发需要和服务器交互的应用程序时,基本上都需要获取服务器端的数 ...
- Android 几种消息推送方案总结
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6241354.html 首先看一张国内Top500 Android应用中它们用到的第三方推送以及所占数量: 现 ...
- vue中使用stompjs实现mqtt消息推送通知
最近在研究vue+webAPI进行前后端分离,在一些如前端定时循环请求后台接口判断状态等应用场景用使用mqtt进行主动的消息推送能够很大程度的减小服务端接口的压力,提高系统的效率,而且可以利用mqtt ...
- Android中实现消息推送(JPush)
1,去JPush官网注册一个账号,创建你的app的应用,并且拿到你应用的AppKey 2,在JPush官网下载对应的sdk,解压出来,将libs文件下的所有的文件全部复制到你工程的libs文件中 3, ...
- mqtt消息推送
https://github.com/wizinfantry/delphi-mqtt-clienthttps://github.com/Indemsys/Delphi_MQTT_mosquittoht ...
- Android消息推送解决方案
前言 消息推送在Android开发中应用的场景是越来越多了,比如说电商产品进行活动宣传.资讯类产品进行新闻推送等等,如下图: 推送消息截图 本文将介绍Android中实现消息推送的7种主流解决方案 目 ...
- Android P正式版即将到来:后台应用保活、消息推送的真正噩梦
1.前言 对于广大Android开发者来说,Android O(即Android 8.0)还没玩热,Andriod P(即Andriod 9.0)又要来了. 下图上谷歌官方公布的Android P ...
- 基于APNs最新HTTP/2接口实现iOS的高性能消息推送(服务端篇)
1.前言 本文要分享的消息推送指的是当iOS端APP被关闭或者处于后台时,还能收到消息/信息/指令的能力. 这种在APP处于后台或关闭情况下的消息推送能力,通常在以下场景下非常有用: 1)IM即时通讯 ...
- 了解iOS消息推送一文就够:史上最全iOS Push技术详解
本文作者:陈裕发, 腾讯系统测试工程师,由腾讯WeTest整理发表. 1.引言 开发iOS系统中的Push推送,通常有以下3种情况: 1)在线Push:比如QQ.微信等IM界面处于前台时,聊天消息和指 ...
随机推荐
- Fork/Join 框架-设计与实现(翻译自论文《A Java Fork/Join Framework》原作者 Doug Lea)
作者简介 Dong Lea任职于纽约州立大学奥斯威戈分校(State University of New York at Oswego),他发布了第一个广泛使用的java collections框架实 ...
- Fragment的坑
http://www.jianshu.com/p/d9143a92ad94 使用add()加入fragment时将触发onAttach(),使用attach()不会触发onAttach() 使用rep ...
- Webpack 常用命令总结以及常用打包压缩方法
前言:Webpack是一款基于node的前端打包工具,它可以将很多静态文件打包起来,自动处理依赖关系后,生成一个.js文件,然后让html来引用,不仅可以做到按需加载,而且可以减少HTTP请求,节约带 ...
- js-ES6学习笔记-数值的扩展
1.ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示. 2.如果要将0b和0o前缀的字符串数值转为十进制,要使用Number方法. 3.ES6在Number对象 ...
- (二)windows上使用docker
参考文献: 1.下载CentOS7镜像 Docker中使用CentOS7镜像 2.使用docker 在Windows里使用Docker 3.使用docker docker学习笔记(windows/ce ...
- SD从零开始55-56, 风险管理, 付款卡
[原创] SD从零开始55 风险管理的内容 应收款风险最小化Risk Minimization for Receivables 每个信用政策的目的是减少由客户应收款带来的风险: 连同信用管理,你也有权 ...
- onlyoffice新版5.1.2版解决中文汉字输入重复等问题
一个星期前新版更新,从5.07到了5.1.2.9.所以我的网盘中的镜像也做了相应的更新. 原来说的几个缺点,已经修改了几个,比如chrome浏览器和opera浏览器中,输入汉字,然后输入符号的时候,会 ...
- jQuery EasyUI datagrid列名包含特殊字符会导致表格错位
首先申明:本文所述的Bug存在于1.3.3以及更高版本中,其它低版本,本人未测试,太老的版本不想去折腾了. 洒家在写前端的SQL执行工具时,表格用了 jQuery EasyUI datagrid,因为 ...
- oracle 11.2.0.1 rman异机恢复 11.2.0.3(windows X64)
问题原因: 误操作,需要时间点恢复. 备份情况:rman 备份,每天一次全备份,并且附带备份当天所有产生的archivelog,无expdp备份 恢复目标: 恢复到9号晚上21点数据 源系统:WIND ...
- 检索 COM 类工厂中 CLSID 为 {00021A20-0000-0000-C000-000000000046} 的组件时失败,原因是出现以下错误: 80080005
创建Excel对象失败: Excel.Application xApp = new Excel.Application(); 错误提示:{"检索 COM 类工厂中 CLSID 为 {0002 ...