Android 实现MQTT客户端,用于门禁消息推送

添加MQTT依赖

implementation ‘org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.2’
implementation ‘org.eclipse.paho:org.eclipse.paho.android.service:1.1.1’

在Manifest清单文件中添加服务

<service android:name="org.eclipse.paho.android.service.MqttService" />

两种实现方法


MqttClient的实现方式

MQTT初始化连接线程,实现与服务器的连接、订阅、发布消息

    private class ConnectTask extends AsyncTask<Void, String, Boolean> {//MQTT连接线程,实现与服务器的连接、订阅、发布消息/*** 异步任务:AsyncTask<Params, Progress, Result>* 1.Params:UI线程传过来的参数。* 2.Progress:发布进度的类型。* 3.Result:返回结果的类型。耗时操作doInBackground的返回结果传给执行之后的参数类型。** 执行流程:* 1.onPreExecute()* 2.doInBackground()-->onProgressUpdate()* 3.onPostExecute()*/@Overrideprotected void onPreExecute() //执行耗时操作之前处理UI线程事件{super.onPreExecute();isConnecting = true;connectionStatusTextView.setText("Connecting...");}@Overrideprotected Boolean doInBackground(Void... voids){//在此方法执行耗时操作,耗时操作中收发MQTT服务器的数据//MQTT服务器地址String brokerUrl = "tcp://www.10086.com:1883";//客户端ID,用于在MQTT服务器上String clientId = MqttClient.generateClientId();try {mqttClient = new MqttClient(brokerUrl, clientId, new MemoryPersistence());} catch (MqttException e) {throw new RuntimeException(e);}MqttConnectOptions connectOptions = new MqttConnectOptions();connectOptions.setCleanSession(true);//mqtt服务器用户名和密码connectOptions.setUserName("username");connectOptions.setPassword("password".toCharArray());connectOptions.setWill("断线消息主题","断线消息内容".getBytes(),1,true);connectOptions.setConnectionTimeout(10);connectOptions.setKeepAliveInterval(20);try {mqttClient.connect(connectOptions);mqttClient.setCallback(new MqttCallback() {@Overridepublic void connectionLost(Throwable throwable) {Log.e(TAG, "连接丢失");//连接丢失的时候可以在这里进行重新连接publishProgress("Connection lost, reconnecting...");new ReconnectTask().execute();}@Overridepublic void messageArrived(String topic, MqttMessage message) throws Exception {Log.i(TAG, "收到消息:"+message.toString());if (topic.equals("sensors/temperature")) {// Update temperature readingpublishProgress("Temperature: " + message.toString());} else if (topic.equals("sensors/humidity")) {// Update humidity readingpublishProgress("Humidity: " + message.toString());} else if (topic.equals("leds/led1/status")) {// Update LED 1 statusif (message.toString().equals("on")) {publishProgress("LED 1 is on");ledStatusImageView.setText("LED 1 is on");} else {publishProgress("LED 1 is off");ledStatusImageView.setText("LED 1 is off");}} else if (topic.equals("leds/led2/status")) {// Update LED 2 statusif (message.toString().equals("on")) {publishProgress("LED 2 is on");ledStatusImageView.setText("LED 2 is on");} else {publishProgress("LED 2 is off");ledStatusImageView.setText("LED 2 is off");}}}@Overridepublic void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {Log.i(TAG, "成功发送");}});//这里是订阅的话题/*** subscribe的第二个参数如果是消息等级,其代表的意义是:** qos = 0 : 消息最多发送一次,在客户端离线等不可用的情况下客户端将会丢失这条消息。** qos = 1 : 消息至少发送一次,能保证客户端能收到该条消息。** qos = 2 : 消息仅传送一次。*/mqttClient.subscribe("zhyj/temperature",1);mqttClient.subscribe("zhyj/mj1/status",1);mqttClient.subscribe("zhyj/mj22/status",1);} catch (MqttException e) {Log.e(TAG, "Error connecting to MQTT broker: " + e.getMessage());publishProgress("Error connecting to MQTT broker: " + e.getMessage());return false;}return true;}@Overrideprotected void onProgressUpdate(String... values) {//用于在主线程处理doInBackground()方法执行完毕后的结果,更新UI或者执行其它操作super.onProgressUpdate(values);connectionStatusTextView.setText(values[0]);}@Overrideprotected void onPostExecute(Boolean aBoolean){//用于在主线程处理doInBackground()方法执行完毕后的结果,更新UI或者执行其它操作super.onPostExecute(aBoolean);isConnecting = false;if (aBoolean) {connectionStatusTextView.setText("Connected");}}}

MQTT重连

    private class ReconnectTask extends AsyncTask<Void, String, Boolean> {@Overrideprotected void onPreExecute() {super.onPreExecute();isConnecting = true;connectionStatusTextView.setText("Reconnecting...");}@Overrideprotected Boolean doInBackground(Void... voids) {if (mqttClient != null && mqttClient.isConnected()) {try {mqttClient.disconnect();} catch (MqttException e) {Log.e(TAG, "Error disconnecting from MQTT broker: " + e.getMessage());}}return new ConnectTask().doInBackground();}@Overrideprotected void onPostExecute(Boolean aBoolean) {super.onPostExecute(aBoolean);isConnecting = false;if (aBoolean) {connectionStatusTextView.setText("Connected");}}}

MQTT断开

 private class DisconnectTask extends AsyncTask<Void, Void, Void> {@Overrideprotected void onPreExecute() {super.onPreExecute();connectionStatusTextView.setText("Disconnecting...");}@Overrideprotected Void doInBackground(Void... voids) {if (mqttClient != null && mqttClient.isConnected()) {try {mqttClient.disconnect();} catch (MqttException e) {Log.e("dbj", "Error disconnecting from MQTT broker: " + e.getMessage());}}return null;}@Overrideprotected void onPostExecute(Void aVoid) {super.onPostExecute(aVoid);connectionStatusTextView.setText("Disconnected");ledStatusImageView.setText("Disconnected");}}

发送消息

private class ToggleLedTask extends AsyncTask<String, Void, Void> {@Overrideprotected Void doInBackground(String... strings) {if (mqttClient != null && mqttClient.isConnected()) {String topic = "zhyj/" + strings[0] + "/control";MqttMessage message = new MqttMessage();if (ledStatusImageView.getText().toString().contains("on")) {message.setPayload("off".getBytes());} else {message.setPayload("on".getBytes());}try {//publish()的第三个参数和subscribe的第二个参数的qos同理mqttClient.publish(topic, message);} catch (MqttException e) {Log.e(TAG, "Error publishing message: " + e.getMessage());}}return null;}}

MqttAndroidClient service的实现方式

配置文件添加 MQTTService

public class MQTTService extends Service {public static final String TAG = "dxj";private static MqttAndroidClient client;private MqttConnectOptions conOpt;private String host = "tcp://www.10086.com:1883";private String userName = "";private String passWord = "";private static String myTopic = "zhyj_mj";      //要订阅的主题private String clientId = "";//客户端标识private IGetMessageCallBack IGetMessageCallBack;@Overridepublic void onCreate() {super.onCreate();Log.e(getClass().getName(), "onCreate");init();}public static void publish(String msg) {try {if (client != null) {client.publish(myTopic, msg.getBytes(), 1, false);}} catch (MqttException e) {e.printStackTrace();Log.e(TAG, "Error connecting to MQTT broker: " + e.getMessage());}}private void init() {// 服务器地址(协议+地址+端口号)String uri = host;client = new MqttAndroidClient(this, uri, clientId);// 设置MQTT监听并且接受消息client.setCallback(mqttCallback);conOpt = new MqttConnectOptions();// 这个标志是标志客户端,服务端是否要保持持久化的一个标志。默认是true//设置客户端和服务端重启或重连后是否需要记住之前的状态conOpt.setCleanSession(false);// 设置超时时间,单位:秒conOpt.setConnectionTimeout(10);// 心跳包发送间隔,单位:秒conOpt.setKeepAliveInterval(20);//连接丢失的情况下,客户端将尝试重新连接到服务器。// 在尝试重新连接之前,它最初将等待1秒,对于每次失败的重新连接尝试,// 延迟将加倍,直到达到2分钟,此时延迟将保持在2分钟
//        conOpt.setAutomaticReconnect(true);// 用户名conOpt.setUserName(userName);// 密码conOpt.setPassword(passWord.toCharArray());     //将字符串转换为字符串数组// last will messageboolean doConnect = true;String message = "{\"terminal_uid\":\"" + clientId + "\"}";Log.e(getClass().getName(), "message是:" + message);String topic = myTopic;// 最后的遗嘱// MQTT本身就是为信号不稳定的网络设计的,所以难免一些客户端会无故的和Broker断开连接。//当客户端连接到Broker时,可以指定LWT,Broker会定期检测客户端是否有异常。//当客户端异常掉线时,Broker就往连接时指定的topic里推送当时指定的LWT消息。try {conOpt.setWill(topic, message.getBytes(), 1, false);} catch (Exception e) {Log.i(TAG, "Exception Occured", e);doConnect = false;iMqttActionListener.onFailure(null, e);}if (doConnect) {doClientConnection();}}@Overridepublic void onDestroy() {stopSelf();try {if (isAlreadyConnected()) {client.disconnect();client.unregisterResources();}IGetMessageCallBack.setStatus("断开连接");} catch (MqttException e) {e.printStackTrace();Log.e(TAG, "Error connecting to MQTT broker: " + e.getMessage());}super.onDestroy();}/*** 连接MQTT服务器*/private void doClientConnection() {if (!isAlreadyConnected() && isConnectIsNormal()) {try {client.connect(conOpt, null, iMqttActionListener);} catch (MqttException e) {e.printStackTrace();Log.e(TAG, "Error connecting to MQTT broker: " + e.getMessage());}}}// MQTT是否连接成功private IMqttActionListener iMqttActionListener = new IMqttActionListener() {@Overridepublic void onSuccess(IMqttToken arg0) {try {/*** subscribe的第二个参数如果是消息等级,其代表的意义是:** qos = 0 : 消息最多发送一次,在客户端离线等不可用的情况下客户端将会丢失这条消息。** qos = 1 : 消息至少发送一次,能保证客户端能收到该条消息。** qos = 2 : 消息仅传送一次。*/client.subscribe("zhyj/mj/status", 1);IGetMessageCallBack.setStatus("连接成功");} catch (MqttException e) {e.printStackTrace();IGetMessageCallBack.setStatus("连接失败");Log.e(TAG, "Error connecting to MQTT broker: " + e.getMessage());}}@Overridepublic void onFailure(IMqttToken arg0, Throwable arg1) {arg1.printStackTrace();// 连接失败,重连Log.e(TAG, "Error publishing message: " + arg0.toString());IGetMessageCallBack.setStatus("连接失败");}};// MQTT监听并且接受消息private MqttCallback mqttCallback = new MqttCallback() {@Overridepublic void messageArrived(String topic, MqttMessage message) throws Exception {IGetMessageCallBack.setStatus("收到消息");String str1 = new String(message.getPayload());if (IGetMessageCallBack != null) {IGetMessageCallBack.setMessage(str1);}String str2 = topic + ";qos:" + message.getQos() + ";retained:" + message.isRetained();Log.i(TAG, "messageArrived:" + str1);Log.i(TAG, str2);}@Overridepublic void deliveryComplete(IMqttDeliveryToken arg0) {IGetMessageCallBack.setStatus("成功发送");}@Overridepublic void connectionLost(Throwable arg0) {// 失去连接,重连Log.e(TAG, "连接丢失 isAlreadyConnected=" + isAlreadyConnected());IGetMessageCallBack.setStatus("连接丢失");}};/*** 判断网络是否连接*/private boolean isConnectIsNormal() {ConnectivityManager connectivityManager = (ConnectivityManager) this.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);NetworkInfo info = connectivityManager.getActiveNetworkInfo();if (info != null && info.isAvailable()) {String name = info.getTypeName();Log.e(TAG, "MQTT当前网络名称:" + name);return true;} else {Log.e(TAG, "MQTT 没有可用网络");return false;}}@Overridepublic IBinder onBind(Intent intent) {Log.e(getClass().getName(), "onBind");return new CustomBinder();}public void setIGetMessageCallBack(IGetMessageCallBack IGetMessageCallBack) {this.IGetMessageCallBack = IGetMessageCallBack;}public class CustomBinder extends Binder {public MQTTService getService() {Log.e(getClass().getName(), "CustomBinder");return MQTTService.this;}}public void toCreateNotification(String message) {PendingIntent pendingIntent = PendingIntent.getActivity(this, 1, new Intent(this, MQTTService.class), PendingIntent.FLAG_UPDATE_CURRENT);NotificationCompat.Builder builder = new NotificationCompat.Builder(this);//3、创建一个通知,属性太多,使用构造器模式Notification notification = builder.setTicker("test_title").setSmallIcon(R.mipmap.ic_launcher).setContentTitle("").setContentText(message).setContentInfo("").setContentIntent(pendingIntent)//点击后才触发的意图,“挂起的”意图.setAutoCancel(true)        //设置点击之后notification消失.build();NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);startForeground(0, notification);notificationManager.notify(0, notification);}public boolean isAlreadyConnected() {if (client != null) {try {boolean result = client.isConnected();if (result) {return true;} else {return false;}} catch (Exception e) {e.printStackTrace();return false;}} else {return false;}}
}
为了方便Service与Acitivity之间的通信,创建一个工具类作为桥梁
public class MyServiceConnection implements ServiceConnection {private MQTTService mqttService;private IGetMessageCallBack IGetMessageCallBack;@Overridepublic void onServiceConnected(ComponentName componentName, IBinder iBinder) {mqttService = ((MQTTService.CustomBinder)iBinder).getService();mqttService.setIGetMessageCallBack(IGetMessageCallBack);}@Overridepublic void onServiceDisconnected(ComponentName componentName) {}public MQTTService getMqttService(){return mqttService;}public void setIGetMessageCallBack(IGetMessageCallBack IGetMessageCallBack){this.IGetMessageCallBack = IGetMessageCallBack;}
几个重要的参数
MqttConnectOptions.setAutomaticReconnect(true)

true表示支持自动重连
连接丢失的情况下,客户端将尝试重新连接到服务器。
在尝试重新连接之前,它最初将等待1秒,对于每次失败的重新连接尝试,
延迟将加倍,直到达到2分钟,此时延迟将保持在2分钟

MqttConnectOptions.setCleanSession(true)

官方注释:
如果设置为false,则客户端和服务器将在重新启动客户端、服务器和连接时保持状态。当状态保持时:
即使重新启动客户端、服务器或连接,消息传递也将可靠地满足指定的QOS。
服务器会将订阅视为持久订阅。
如果设置为true,则客户端和服务器将不会在重新启动客户端、服务器或连接时保持状态。这意味着
如果重新启动客户端、服务器或连接,则无法维持向指定QOS的消息传递

这个标志是标志客户端,服务端是否要保持持久化的一个标志。默认是true
设置客户端和服务端重启或重连后是否需要记住之前的状态。
当setCleanSession为true时,客户端掉线或服务端重启后,服务端和客户端会清掉之前的 session, 重连后客户端会有一个新的session。离线期间发来QoS=0,1,2的消息一律接收不到,且所有之前订阅的topic需要重新订阅。
··························································································
当setCleanSession为false时, 客户端掉线或服务端重启后,服务端和客户端不会清除之前的session。重连后session将会恢复,客户端不用重新订阅主题。且离线期间发来QoS=0,1,2的消息仍然可以接收到。

这里有个需要注意的地方,即setCleanSession为true时,掉线后客户端设置了setAutomaticReconnect为true才会自动重连。为当setCleanSession为false时。不管setAutomaticReconnect为true或者false都会自动重连。

MqttConnectOptions.setKeepAliveInterval(30);

心跳包发送间隔,单位:秒
MQTT客户端(client)在没有收到或发布任何消息时仍然是保持连接的。服务端(the broker)需要跟踪客户端的连接状态。 所有需要发送心跳包来确定客户端是否是连接状态。心跳包发送的时间间隔就是keepalive设置的。
服务端会维持一个timer。当这个timer记录的时间超过1.5倍keepalive值时,服务端会将这个客户端标记为断开连接,并发送Last Will and Testament (LWT)遗言广播。
每次客户端发送或接收一个消息, 服务端会重置这个timer。

按具体业务场景修改使用即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/24034.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#之Winfrom自定义输入框对话框。

如果你需要一个带有输入框的对话框&#xff0c;并在输入完成后接收输入的值&#xff0c;你可以使用自定义窗体来实现。以下是一个示例代码&#xff1a;创建一个继承自 Form 的自定义窗体类&#xff0c;命名为 InputDialogForm&#xff0c;并将窗体上放置一个文本框&#xff08;…

《前端开发 实践之 构建工具的了解》

目录 构建工具的了解Vite 构建工具了解基本使用 构建工具的了解 前端构建工具之一&#xff1a;vite Vite 构建工具了解 vue官方&#xff1b;打包工具&#xff1b;vue 项目本地构建部署工具 类似的前端项目打包工具还有&#xff1a;webpack等等 与其他打包工具区别可能有这几个方…

@FeignClient指定多个url实现负载均衡

C知道回答的如下&#xff1a; 在使用 FeignClient 调用多个 URL 实现负载均衡时&#xff0c;可以使用 Spring Cloud Ribbon 提供的功能来实现。下面是一个示例代码&#xff1a; 首先&#xff0c;在Spring Boot主类上添加EnableFeignClients注解启用Feign Client功能。 Spring…

安捷伦Agilent37719A通讯分析仪

安捷伦Agilent37719A通讯分析仪(131----4587---6435&#xff09; ATM和POS测试能力达到2.5 Gb/s OC-48、OC-48c、OC-12、OC-12c、OC-3c、OC-3、OC-1、STS-3、STS-3c、STS-1测试 保护切换时间测量 所有同步速率高达2.5 Gb/s的串联有效负载 SONET环翻转的全面直通模式操作 全开销…

git代码版本管理

git 文章目录 git基本使用 基本使用 在一台新的电脑上使用git 你要下载安装git, 然后把git的安装路径配到系统环境变量里 然后把这台电脑的.ssh/ id_rsa.pub里的公钥整到github里 然后在github上新建仓库&#xff0c;它会生成一些指令引导上你传本地的代码 之后就可以在终…

Redis | 集群模式

Redis | 集群模式 随着互联网应用规模的不断扩大&#xff0c;单一节点的数据库性能已经无法满足大规模应用的需求。为了提高数据库的性能和可扩展性&#xff0c;分布式数据库成为了解决方案之一。Redis 作为一个高性能的内存数据库&#xff0c;自然也有了自己的分布式部署方式…

【笔记】第94期-冯永吉-《湖仓集一体关键技术解读》-大数据百家讲坛-厦大数据库实验室主办20221022

https://www.bilibili.com/video/BV1714y1j7AU/?spm_id_from333.337.search-card.all.click&vd_sourcefa36a95b3c3fa4f32dd400f8cabddeaf

【数理知识】协方差,随机变量的的协方差,随机变量分别是单个数字和向量时的协方差

序号内容1【数理知识】自由度 degree of freedom 及自由度的计算方法2【数理知识】刚体 rigid body 及刚体的运动3【数理知识】刚体基本运动&#xff0c;平动&#xff0c;转动4【数理知识】向量数乘&#xff0c;内积&#xff0c;外积&#xff0c;matlab代码实现5【数理知识】协…

C#基于OpenCv(OpenCvSharp) 的 fftshift, ifftshift 函数的实现

本文实现基于OpenCv(OpenCvSharp) 的 fftshift, ifftshift 函数。 fftshift 函数将信号频谱的零频分量移动到数组中心, 本质是分别对调一三象限数据。 ifftshift完成相反的操作,本质是二四象限的数据块。 OpenCV中没有这两个函数如果使用需要自己实现。 实现代码如下: …

【雕爷学编程】MicroPython动手做(30)——物联网之Blynk 2

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

用Rust实现23种设计模式之简单工厂

在 Rust 中&#xff0c;可以使用结构体和 trait 来实现工厂方法模式。工厂方法模式是一种创建型设计模式&#xff0c;通过定义一个创建对象的接口&#xff0c;让子类决定实例化哪个类。下面是一个简单的示例&#xff0c;展示了如何使用 Rust 实现工厂方法模式&#xff1a; // …

TypeScript技能总结(二)

typescript是js的超集&#xff0c;目前很多前端框架都开始使用它来作为项目的维护管理的工具&#xff0c;还在不断地更新&#xff0c;添加新功能中&#xff0c;我们学习它&#xff0c;才能更好的在的项目中运用它&#xff0c;发挥它的最大功效 //readonly 只能修饰属性&#x…

EXCEL里数值列如何显示序号?如何重新排序? 怎么取得排序后的序号?

目录 1 EXCEL里如何显示序号&#xff1f; 2 如何重新排序&#xff1f; 3 怎么取得排序后的序号&#xff1f; 3.1 rank() 的序号可能不连续 3.2 方法2&#xff1a;SUMPRODUCT((C7>C$7:C$12)/COUNTIF(C$7:C$12,C$7:C$12))1 EXCEL里如何显示序号&#xff1f;如何重新排序…

Go语言基础:运算符、文件操作、接口、Packages、if else、for循环

文章目录 1.运算符2.文件操作3.接口4.Packages5.If else6.For循环 1.运算符 func main() {// 算术运算符a, b : 3, 7c : a bd : a - be : a * bf : a / bg : a % baa--fmt.Println(c, d, e, f, g)// 关系运算符fmt.Println(a b)fmt.Println(a ! b)fmt.Println(a < b)fmt.…

MySQL数据库面试题:如何定位慢查询?

MySQL数据库面试题&#xff1a;如何定位慢查询&#xff1f; 面试官&#xff1a;MySQL中&#xff0c;如何定位慢查询&#xff1f; 候选人&#xff1a;嗯~&#xff0c;我们当时做压测的时候有的接口非常的慢&#xff0c;接口的响应时间超过了2秒以上&#xff0c;因为我们当时的系…

win11 vscode torch 编译遇错

1. 错误内容&#xff1a; Failed to build pc-util ERROR: Could not build wheels for pc-util, which is required to install pyproject.toml-based projects NativeCommandExitException: Program “pip.exe” ended with non-zero exit code: 2.问题分析&#xff1a; pip出…

Linux命令(59)之screen

linux命令之screen 1.screen介绍 linux命令screen是用来进行多窗口管理。 默认screen命令没有安装&#xff0c;安装命令(基于yum源)&#xff1a;yum install -y screen 2.screen用法 screen [参数] screen参数 参数说明-r恢复离线的screen作业-ls显示所有的screen作业 3.…

echarts 饼图的label放置于labelLine引导线上方

一般的饼图基础配置后长这样。 想要实现将文本放置在引导线上方&#xff0c;效果长这样 const options {// ...series: [{label: {padding: [0, -40],},labelLine: {length: 10,length2: 50,},labelLayout: {verticalAlign: "bottom",dy: -10,},},], };label.padd…

Zip压缩包密码忘记了,怎么办?

Zip压缩包设置了密码&#xff0c;解压的时候就需要输入正确对密码才能顺利解压出文件&#xff0c;正常当我们解压文件或者删除密码的时候&#xff0c;虽然方法多&#xff0c;但是都需要输入正确的密码才能完成。忘记密码就无法进行操作。 那么&#xff0c;忘记了zip压缩包的密…

CNN成长路:从AlexNet到EfficientNet(01)

一、说明 在 10年的深度学习中&#xff0c;进步是多么迅速&#xff01;早在 2012 年&#xff0c;Alexnet 在 ImageNet 上的准确率就达到了 63.3% 的 Top-1。现在&#xff0c;我们超过90%的EfficientNet架构和师生训练&#xff08;teacher-student&#xff09;。 如果我们在 Ima…