目录
一、如何实现远程网页控制售卖机出商品?
比如,我们想实现,通过一个网页去控制自动售卖机(自动售卖机装有Android系统,装有App)出商品,也就是我们熟知的远程控制,不用你人到现场,就可以解决很多问题,所以这个功能会大大的提高我们的便捷性,实现无人值守。
那么有什么技术可以实现这个这个?现成的第三方框架有个推,也可以自己搭建一个RabbitMQ平台,这样维护也方便一些,出现问题也可以及时修复和处理。
这篇文章,我们就来讲讲App如何接入RabbitMQ。
二、Rabbit MQ是什么?
RabbitMQ是一种开源的消息中间件,它实现了高级消息队列协议(AMQP)的标准。
【特点】
RabbitMQ允许不同的应用程序之间通过消息传递进行通信,并提供了可靠的消息传递机制,以确保消息在发送者和接收者之间可靠地传递和处理。它使用消息队列来存储消息,队列是先进先出(FIFO)的数据结构,保证消息按照它们到达的顺序进行处理。
简单来说,你有两个应用程序,它们需要互相交流信息,但它们有不在一起,因为它们可能运行在不同的服务器上,甚至可能使用不同的编程语言。这时,RabbitMQ就派上用场了。
三、如何使用?
3.1 添加依赖
implementation ("com.rabbitmq:amqp-client:5.13.0")
3.2 MQ配置类
主要是填写后台搭建的mq平台的连接信息,我们要连接上它,需要有:域名、端口号(一般固定的)、登录名、登录密码,以及你要监听那个队列的信息,注意,每一台自动售卖机对应一个队列,他们是互不干扰的,所以QUEUE_NAME是唯一的。
class RabbitMQHelper {
val connectionFactory: ConnectionFactory
get() {
val factory = ConnectionFactory()
factory.host = HOST
factory.port = PORT
factory.username = USERNAME
factory.password = PASSWORD
return factory
}
companion object {
//队列名称
var QUEUE_NAME: String = "xxxx"
//MQ地址
const val HOST: String = "xxx.xxx.xxx.xxx"
//MQ端口号
const val PORT: Int = 5672
//MQ账号
const val USERNAME: String = "xxx"
//MQ密码
const val PASSWORD: String = "xxx"
}
}
3.3 MQ连接,并监听消息处理
Thread(object :Runnable{
override fun run() {
val helper = RabbitMQHelper()
val factory = helper.connectionFactory
Log.d(TAG, "doInBackground: factory"+factory)
try {
factory.newConnection().use { connection ->
connection.createChannel().use { channel ->
val queueName =RabbitMQHelper.QUEUE_NAME
// 声明队列
// 这里我不需要声明,因为后台已经创建了队列,大家根据实际情况来
//如果连接mq的时候出现错误,那么有可能是你的配置有问题,比如声明不对,定义消费者不对。
// channel.queueDeclare(queueName, true, false, false, null)
// 1. 定义消费者
channel.basicConsume(queueName, false, object : DefaultConsumer(channel) {
@Throws(IOException::class)
override fun handleDelivery(
consumerTag: String,
envelope: Envelope,
properties: AMQP.BasicProperties,
body: ByteArray
) {
val message =
String(body, charset("UTF-8"))
Log.d(TAG, "handleDelivery: "+message)
// 手动确认消息
channel.basicAck(envelope.deliveryTag, false)
// 添加处理消息的代码
Log.i(TAG,message);
}
})
synchronized(this) {
(this as Object).wait()
}
}
}
} catch (e: Exception) {
e.printStackTrace()
Log.d(TAG, "doInBackground: error:"+e)
}
}
}).start()
- factory.newConnection():这个方法调用连接工厂来创建一个新的到RabbitMQ服务器的连接。
- connection.createChannel():这个方法在已经建立的连接上创建一个新的通道(channel)。用于发送和接收消息。
- channel.basicConsume():这个方法,用于从指定的队列(queueName)中接收消息。
- channel.basicAck(envelope.deliveryTag, false)用于告诉 RabbitMQ 服务器某个特定的消息已经被消费者成功处理,并且可以从队列中移除。
- message就是传递过来的消息,我们收到以后进行解析处理。比如我们可以控制机器休眠,1就是启动休眠 0就是关闭休眠。
到了,其实到这里,基本的使用就已经可以了,你可以在后台发送消息过来,Android进行接收处理。
四、实际使用中遇到的问题
4.1如何实现断网重连?
假如说,因为一些原因,比如断网了,导致mq断开了连接,或者后台服务器出现问题,我们需要重新连接,应该如何解决呢?以前我们可能使用网络监听广播,如果出现断网或者有网络,那么就重新连接。
//注册广播
mNetWorkBroadCastReciver = NetWorkBroadCastReciver()
val intentFilter = IntentFilter()
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION)
intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION)
intentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION)
registerReceiver(mNetWorkBroadCastReciver, intentFilter)
//接收网络状态改变的广播
inner class NetWorkBroadCastReciver() : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
isNetConnected(context)
}
}
private var networkState = 100
fun isNetConnected(context: Context): Boolean {
val connectivity: ConnectivityManager? =
context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
if (connectivity != null) {
val info = connectivity.activeNetworkInfo
if (info != null) {
if (info.type == networkState) {
return false
}
networkState = info.type
if (info.type == (ConnectivityManager.TYPE_WIFI)) {
if (!connect) {
//发起重连
}
return true
} else if (info.type == (ConnectivityManager.TYPE_MOBILE)) {
if (!connect) {
//发起重连
}
return true
}
}
}
return false
}
不过rabbitmq框架也提供了更加便捷的方法,让我们添加这个方法就可以实现断网重连的功能。
我们修改一下mq的配置类
class RabbitMQHelper {
val connectionFactory: ConnectionFactory
get() {
val factory = ConnectionFactory()
factory.host = HOST
factory.port = PORT
factory.username = USERNAME
factory.password = PASSWORD
factory.isAutomaticRecoveryEnabled = true // 开启连接的自动恢复功能
// 设置重试时间间隔(毫秒) 默认5秒,可以修改.
// factory.setNetworkRecoveryInterval(10000);
return factory
}
但注意,这个只能处理链接上以后的重连,如果一开始就没有网络,那么这种自动恢复就生效不了。还是需要使用到监听网络广播。
4.2 连接不上后台的MQ
可以朝着这几个方向分析。
- 需要检查是否MQ配置信息出现了问题?
- 检查队列信息是否设置正确的,channel.queueDeclare(queueName, true, false, false, null)
- 或者队列已经声明存在。
五、了解更多的RabbitMQ信息
如果想了解更多的RabbitMQ的知识,可以看看这篇文章【消息队列:Rabbit MQ详解一篇搞定】:https://editor.****.net/md/?articleId=131504930