Android MQTT开发之 Hivemq MQTT Client

使用一个开源库:hivemq-mqtt-client,这是Java生态的一个MQTT客户端框架,需要Java 8,Android上使用的话问题不大,需要一些额外的配置,下面列出了相关的配置,尤其是 packagingOptions,不然编译不过,因为框架使用了Java8新增的语言特性,所以 minSdk 设置为24,即Android7.0,如果要兼容Android7.0以下系统,可以参考这份详细文档配置一下语法脱糖的SDK: Installation on Android

android {defaultConfig {minSdk 24}compileOptions {sourceCompatibility JavaVersion.VERSION_8targetCompatibility JavaVersion.VERSION_8}kotlinOptions {jvmTarget = '8'}packagingOptions {resources {excludes += ['META-INF/INDEX.LIST', 'META-INF/io.netty.versions.properties']}}
}dependencies {implementation 'com.hivemq:hivemq-mqtt-client:1.3.3'
}

刚开始在自动连接这块花了好多时间,最后才发现是设置用户名和密码的地方不对,一定要在设置自动重连(初始化Client)的地方设置,而不是连接的时候!下面是一个简单的使用示例代码

MqttManager.kt

import android.util.Log
import com.hivemq.client.mqtt.datatypes.MqttQos
import com.hivemq.client.mqtt.lifecycle.MqttClientConnectedContext
import com.hivemq.client.mqtt.lifecycle.MqttClientConnectedListener
import com.hivemq.client.mqtt.lifecycle.MqttClientDisconnectedContext
import com.hivemq.client.mqtt.lifecycle.MqttClientDisconnectedListener
import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient
import com.hivemq.client.mqtt.mqtt5.Mqtt5Client
import com.hivemq.client.mqtt.mqtt5.message.connect.connack.Mqtt5ConnAckReasonCode
import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5Publish
import com.hivemq.client.mqtt.mqtt5.message.subscribe.suback.Mqtt5SubAck
import java.util.UUID
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Executors
import java.util.function.Consumeropen class MqttListener {open fun onConnected() {}open fun onDisconnected() {}open fun onSubscribed(vararg topics: String) {}open fun onReceiveMessage(topic: String, data: ByteArray) {}open fun onSendMessage(topic: String, data: ByteArray) {}
}/*
文档
https://github.com/hivemq/hivemq-mqtt-client
https://hivemq.github.io/hivemq-mqtt-client/docs/installation/android/
*/
class MqttManager private constructor() : MqttClientConnectedListener, MqttClientDisconnectedListener {private val executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()) {Thread(it).apply { isDaemon = true }}private val mqttAsynClient: Mqtt5AsyncClient = Mqtt5Client.builder().identifier(UUID.randomUUID().toString()).serverHost(SERVER_HOST).serverPort(SERVER_PORT).addConnectedListener(this).addDisconnectedListener(this).simpleAuth()//在初始化的时候设置账号密码,重连才能成功.username(USERNAME).password(PASSWORD.toByteArray()).applySimpleAuth().automaticReconnectWithDefaultConfig()//自动重连.buildAsync()private val listeners = mutableListOf<MqttListener>()private val subTopicsget() = arrayOf("top1", "top2", "top3")fun addMqttListener(listener: MqttListener) {if (!listeners.contains(listener)) {listeners.add(listener)}}fun removeMqttListener(listener: MqttListener) {listeners.remove(listener)}override fun onConnected(context: MqttClientConnectedContext) {Log.i(TAG, "onConnected()")for (l in listeners) {l.onConnected()}subscribeAll()}private fun subscribeAll() {CompletableFuture.supplyAsync({val futures = subTopics.map(::subscribe).map {it.thenCompose {CompletableFuture.supplyAsync({val success = !it.reasonString.isPresentif (success) {Log.i(TAG, "subscribe success")} else {Log.e(TAG, "subscribe() - reasonCodes=[${it.reasonCodes.joinToString(", ")}]" +", reasonString=${it.reasonString}")}success}, executor)}}.toTypedArray()CompletableFuture.allOf(*futures).join()//等待所有订阅结果if(futures.all { it.get() }) {Log.i(TAG, "subscribeAll() - 全部订阅成功")}for (l in listeners) {l.onSubscribed(*subTopics)}}, executor)}override fun onDisconnected(context: MqttClientDisconnectedContext) {Log.e(TAG, "onDisconnected() - isConnected=${mqttAsynClient.state.isConnected}" +", isConnectedOrReconnect=${mqttAsynClient.state.isConnectedOrReconnect}")for (l in listeners) {l.onDisconnected()}}fun connect() {mqttAsynClient.connectWith().cleanStart(true).keepAlive(30).send().thenAccept {if (it.reasonCode == Mqtt5ConnAckReasonCode.SUCCESS) {Log.i(TAG, "connect() - SUCCESS")} else {Log.e(TAG, "connect() - ${it.reasonCode}")}}}fun disconnect() {mqttAsynClient.disconnect().thenAccept {Log.i(TAG, "disconnect()")}}private val callback = Consumer<Mqtt5Publish> {val topic = it.topic.toString()val data = it.payloadAsBytesprocessReceivedMessage(topic, data)}private fun processReceivedMessage(topic: String, data: ByteArray) {//处理接收的数据for (l in listeners) {l.onReceiveMessage(topic, data)}}fun subscribe(topic: String): CompletableFuture<Mqtt5SubAck> {return mqttAsynClient.subscribeWith().topicFilter(topic).noLocal(true)// we do not want to receive our own message.qos(MqttQos.AT_MOST_ONCE).callback(callback).executor(executor).send()}fun unsubscribe(topic: String) {mqttAsynClient.unsubscribeWith().topicFilter(topic).send().thenAccept {Log.i(TAG, "unsubscribe() - $it")}}/*** 发送数据*/fun publish(topic: String, payload: ByteArray) {mqttAsynClient.publishWith().topic(topic).qos(MqttQos.AT_MOST_ONCE).payload(payload).send().thenAccept { mqtt5PublishResult ->mqtt5PublishResult.publish.let { mqtt5Publish ->
//                    val topic = mqtt5Publish.topic.toString()val data = mqtt5Publish.payloadAsBytesfor (l in listeners) {l.onSendMessage(topic, data)}}}}companion object {private const val TAG = "MqttManager"private const val SERVER_HOST = "example.com"private const val SERVER_PORT = 1883 // 1883即TCP协议,host不要再加上"tcp://",否则连不成功private const val USERNAME = "admin"private const val PASSWORD = "123456"val instance = MqttManager()}
}

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

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

相关文章

python之代理ip的配置与调试

目录 前言 一、代理IP的配置 二、代理IP的调试 2.1 使用curl命令测试代理IP 2.2 使用requests库调试代理IP 三、代理IP的获取 3.1 使用代理IP池 3.2 使用付费代理IP服务 总结 前言 代理IP是网络爬虫中常用的技术手段。通过使用代理服务器&#xff0c;可以实现对特定网…

某60区块链安全之不安全的随机数实战一

区块链安全 文章目录 区块链安全不安全的随机数实战一实验目的实验环境实验工具实验原理实验内容攻击过程分析合约源代码漏洞EXP利用 不安全的随机数实战一 实验目的 学会使用python3的web3模块 学会以太坊不安全的随机数漏洞分析及利用 实验环境 Ubuntu18.04操作机 实验工…

【Flink】核心概念:并行度与算子链

并行度&#xff08;Parallelism&#xff09; 当要处理的数据量非常大时&#xff0c;我们可以把一个算子操作&#xff0c;“复制”多份到多个节点&#xff0c;数据来了之后就可以到其中任意一个执行。这样一来&#xff0c;一个算子任务就被拆分成了多个并行的“子任务”&#x…

爱上C语言:操作符详解(下)

&#x1f680; 作者&#xff1a;阿辉不一般 &#x1f680; 你说呢&#xff1a;生活本来沉闷&#xff0c;但跑起来就有风 &#x1f680; 专栏&#xff1a;爱上C语言 &#x1f680;作图工具&#xff1a;draw.io(免费开源的作图网站) 如果觉得文章对你有帮助的话&#xff0c;还请…

STM32/N32G455国民科技芯片驱动DS1302时钟---笔记

这次来分享一下DS1302时钟IC&#xff0c;之前听说过这个IC&#xff0c;但是一直没搞过&#xff0c;用了半天时间就明白了原理和驱动&#xff0c;说明还是很简单的。 注&#xff1a;首先来区分一下DS1302和RTC时钟有什么不同&#xff0c;为什么不直接用RTC呢&#xff1f; RTC不…

计蒜客T1723 约瑟夫问题(C语言实现)

【题目描述】 传说约瑟夫当年活下来就是靠快速计算这个问题。n个人围成一圈&#xff0c;编号依次为1,2,3…n。从第一个人开始报数&#xff0c;数到m的人再出圈。以此类推&#xff0c;直到所有的人都出列。请输出依次出圈人的编号。 【输入格式】 两个整数n,m&#xff0c;均在[1…

[Vue 代码模板] Vue3 中使用 Tailwind CSS + NutUI 实现侧边工具栏切换主题

文章归档&#xff1a;https://www.yuque.com/u27599042/coding_star/vzkgy6gvcnpl3u2y 效果示例 配置 src 目录别名 https://www.yuque.com/u27599042/coding_star/ogu2bhefy1fvahfv 配置 Tailwind CSS https://www.yuque.com/u27599042/coding_star/yqzi9olphko9ity1 配置…

CAPL编程 - 事件驱动

1 事件概述 CAPL是一种面向过程、由事件驱动的类C语言。 事件驱动针对于顺序执行&#xff0c;其区别如下&#xff1a; 顺序执行&#xff1a;顺序执行流程中&#xff0c;子例程或过程函数按照代码编写顺序逐句执行。 事件驱动&#xff1a;CAPL程序由事件驱动&#xff0c;工程…

11.15 监控目录文件变化

监视对指定目录的更改&#xff0c;并将有关更改的信息打印到控制台&#xff0c;该功能的实现不仅可以在内核层&#xff0c;在应用层同样可以。程序中使用ReadDirectoryChangesW函数来监视目录中的更改&#xff0c;并使用FILE_NOTIFY_INFORMATION结构来获取有关更改的信息。 Re…

Selenium中元素定位方法详细介绍

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

JavaScript实现飞机发射子弹详解(内含源码)

JavaScript实现飞机发射子弹 前言实现过程源码展示源码讲解HTML结构CSS结构js结构 前言 文本主要讲解如何利用JavaScript实现飞机发射子弹&#xff0c;实现过程以及源码讲解。实现效果图如下&#xff1a; 实现过程 首先&#xff0c;找到飞机和子弹的UI图&#xff0c;gif图最…

外贸B2C独立站如何做?

外贸B2C独立站是一种直接向海外消费者销售产品的商业模式。它通常包括建立一个自己的在线商店&#xff0c;通过社交媒体、广告和搜索引擎等渠道吸引流量&#xff0c;并使用国际支付和物流服务来处理订单。以下是一些关于如何建立和运营外贸B2C独立站的建议&#xff1a; 确定目标…

【Android】使用Retrofit2发送异步网络请求的简单案例

添加网络权限到AndroidManifest.xml清单文件 为了让你的Android应用程序能够使用互联网进行通信&#xff0c;你需要在AndroidManifest.xml文件中添加网络权限声明。<uses-permission android:name"android.permission.INTERNET"/> 这个权限应该添加到 Android…

C/C++模板类模板与函数模板区别,以及用法详解

类模板 类模板语法 类模板作用&#xff1a; 建立一个通用类&#xff0c;类中的成员 数据类型可以不具体制定&#xff0c;用一个虚拟的类型来代表。 语法&#xff1a; template<typename T> 类解释&#xff1a; template --- 声明创建模板 typename --- 表面其后面的…

python爬虫概述及简单实践:获取豆瓣电影排行榜

目录 前言 Python爬虫概述 简单实践 - 获取豆瓣电影排行榜 1. 分析目标网页 2. 获取页面内容 3. 解析页面 4. 数据存储 5. 使用代理IP 总结 前言 Python爬虫是指通过程序自动化地对互联网上的信息进行抓取和分析的一种技术。Python作为一门易于学习且强大的编程语言&…

云服务器网络掉包问题分析及解决方案

在互联网领域拥有先进的基础设施和技术&#xff0c;其服务器网络一直以来都备受关注。近期有用户反映云服务器网络掉包问题严重&#xff0c;给用户的网络体验带来了很大的困扰。 我们需要了解什么是网络掉包。网络掉包是指在数据传输过程中&#xff0c;由于网络拥堵、路由不稳…

LabVIEW关于USRPRIO的示例代码

LabVIEW关于USRPRIO的示例代码 USRPRIO 通常以两种方式使用&#xff1a; 1 基于 FPGA 的编程 对于希望修改USRP上的底层FPGA代码以添加自定义DSP模块的应用&#xff0c;请使用USRP示例项目。它可作为构建 USRP RIO 流式处理应用程序的起点&#xff0c;可从“创建项目”对话框…

项目资讯丨轻空间中标连云港市首座“多功能声学综合馆”(EPC)

近日&#xff0c;轻空间&#xff08;江苏&#xff09;膜科技有限公司&#xff08;以下简称“轻空间”&#xff09;成功中标连云港市首座“多功能声学综合馆”项目&#xff0c;这标志着轻空间在新型气膜领域的创新突破技术&#xff0c;再次获得政府机构的高度认可&#xff0c;为…

vue 鼠标移入移出事件执行多次(尤其ie)

mouseover 当一个定点设备&#xff08;通常指鼠标&#xff09;在一个元素本身或者其子元素上移动时&#xff0c;mouseover 事件在该元素上触发。 mouseenter 事件在定点设备&#xff08;通常指鼠标&#xff09;首次移动到元素的激活区域内时&#xff0c;在该元素上触发。 mouse…

TypeScript 泛型及应用

TypeScript 泛型及应用 泛型&#xff08;Generics&#xff09;是 TypeScript 中的一项强大特性&#xff0c;它允许我们在定义函数、类和接口时使用类型参数&#xff0c;从而增加代码的灵活性和重用性。本文将介绍 TypeScript 中泛型的概念、语法以及一些常见的应用场景。 泛型…