前言
所有博客仅为记录学习笔记!!!
能力有限,很多地方是带惑硬撸,如有错误,还请指出!
大家总说,开发避免重复造轮子,我觉得其实不然,重复造轮子大概是给有能力造轮子的人说的,入门的话,如果只会复制粘贴的话,并不其所以然,就连轮子的接口数据都不知道,怎么能进步呢 ?
唯有实践出真理!
1. MQTT简介
什么是MQTT?
MQTT 的全称为 Message Queue Telemetry Transport,MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。在很多情况下,包括受限的环境中,如:机器与机器(M2M)通信和物联网(IoT)。其在,通过卫星链路通信传感器、偶尔拨号的医疗设备、智能家居、及一些小型化设备中已广泛使用。MQTT就包含了以下一些特点:
- 实现简单
- 提供数据传输的 QoS
- 轻量、占用带宽低
- 可传输任意类型的数据
- 可保持的会话(session)
2.MQTT jar导入
jar的导入有两种方式,简单粗暴的本地导入,和加载镜像库地址导入,两者各有好处吧,由于刚入门的时候网络的问题在各种包的远程构建上踩了不少坑,了解本地导入后渐渐悟出了真香定理。
本地导入:
顾名思义本地导入就是加载本地的jar ,需要手动复制粘贴所需jar到工程中。
首先下载所需的jar包,这里就不做过多介绍,下载过后的包如图所示:
打开android 工程,切换到project工程视图下,找到libs文件夹,粘贴我们刚才下载的jar包即可!
复制后弹出以下界面,点击OK即可
至此导入已经完成一半,仅仅导入jar包还不能为之所用,需要添加到工程文件中,如图所示:
选中上一步添加的jar包,右击鼠标,看到图中第二步“Add As Library…”,作为工程的库文件使用,点击即可。下图可以看到软件已自动添加依赖库,如若此处并未有此行代码,可能导入不成功。
远程依赖库导入:
1 2 3 | dependencies{ compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0' } |
3.权限和注册
3.1添加权限
复制权限代码到工程AndroidManifest.xml文件中
1 2 3 4 5 | /*添加权限*/ <!--允许程序打开网络套接字--> <uses-permission android:name="android.permission.INTERNET" /> <!--允许程序获取网络状态--> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> |
3.2注册Service:
1 2 | <!-- Mqtt 服务 --> <service android:name="org.eclipse.paho.android.service.MqttService" /> |
4.MQTT实现函数
4.1初始化函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | private void Mqtt_init() { try { //host为主机名,test为clientid即连接MQTT的客户端ID,一般以客户端唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存 client = new MqttClient(host, mqtt_id, new MemoryPersistence()); //MQTT的连接设置 options = new MqttConnectOptions(); //设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接 options.setCleanSession(false); //设置连接的用户名 options.setUserName(userName); //设置连接的密码 options.setPassword(passWord.toCharArray()); // 设置超时时间 单位为秒 options.setConnectionTimeout(10); // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制 options.setKeepAliveInterval(20); //设置回调 client.setCallback(new MqttCallback() { @Override public void connectionLost(Throwable cause) { //连接丢失后,一般在这里面进行重连 System.out.println("connectionLost----------"); //startReconnect(); } @Override public void deliveryComplete(IMqttDeliveryToken token) { //publish后会执行到这里 System.out.println("deliveryComplete---------" + token.isComplete()); } @Override public void messageArrived(String topicName, MqttMessage message) throws Exception { //subscribe后得到的消息会执行到这里面 System.out.println("messageArrived----------"); Message msg = new Message(); msg.what = 3; //收到消息标志位 msg.obj = topicName + "---" + message.toString(); handler.sendMessage(msg); // hander 回传 } }); } catch (Exception e) { e.printStackTrace(); } } |
4.2连接和重连函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | private void Mqtt_connect() { new Thread(new Runnable() { @Override public void run() { try { if(!(client.isConnected()) ) //如果还未连接 { client.connect(options); Message msg = new Message(); msg.what = 31; handler.sendMessage(msg); } } catch (Exception e) { e.printStackTrace(); Message msg = new Message(); msg.what = 30; handler.sendMessage(msg); } } }).start(); } private void startReconnect() { scheduler = Executors.newSingleThreadScheduledExecutor(); scheduler.scheduleAtFixedRate(new Runnable() { @Override public void run() { if (!client.isConnected()) { Mqtt_connect(); } } }, 0 * 1000, 10 * 1000, TimeUnit.MILLISECONDS); } |
4.3 Main_Acticity 对应程序
程序中对应有详细标注
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | package com.demo.mqtt_project; import androidx.appcompat.app.AppCompatActivity; import android.annotation.SuppressLint; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.provider.Settings; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; import org.eclipse.paho.client.mqttv3.MqttCallback; import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttConnectOptions; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; import org.json.JSONException; import org.json.JSONObject; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class MainActivity extends AppCompatActivity { private String host = "tcp://ip地址"; private String userName = "android"; private String passWord = "android"; private String mqtt_id = "**********"; //id要唯一,不然会掉线 private String mqtt_sub_topic = "**********"; //更改为自己的,分别为订阅和发布 topic private String mqtt_pub_topic = "**********"; private ScheduledExecutorService scheduler; private TextView text_test; private MqttClient client; private MqttConnectOptions options; private Handler handler; @SuppressLint("HandlerLeak") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 对应界面UI btn_1 = findViewById(R.id.btn_1); // 寻找xml里面真正的id 与自己定义的id绑定 btn_1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { System.out.println("hello"); Toast.makeText(MainActivity.this,"hello" ,Toast.LENGTH_SHORT).show(); } }); /**********************************************/ Mqtt_init(); startReconnect(); handler = new Handler() { @SuppressLint("SetTextI18n") public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case 1: //开机校验更新回传 break; case 2: // 反馈回传 break; case 3: //MQTT 收到消息回传 UTF8Buffer msg=new UTF8Buffer(object.toString()); Toast.makeText(MainActivity.this,msg.obj.toString() ,Toast.LENGTH_SHORT).show(); text_test.setText(msg.obj.toString()); //接收到下位机信息打印到TEXT break; case 30: //连接失败 Toast.makeText(MainActivity.this,"连接失败" ,Toast.LENGTH_SHORT).show(); break; case 31: //连接成功 Toast.makeText(MainActivity.this,"连接成功" ,Toast.LENGTH_SHORT).show(); try { client.subscribe(mqtt_sub_topic,1); } catch (MqttException e) { e.printStackTrace(); } break; default: break; } } }; } private void Mqtt_init() { try { //host为主机名,test为clientid即连接MQTT的客户端ID,一般以客户端唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存 client = new MqttClient(host, mqtt_id, new MemoryPersistence()); //MQTT的连接设置 options = new MqttConnectOptions(); //设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接 options.setCleanSession(false); //设置连接的用户名 options.setUserName(userName); //设置连接的密码 options.setPassword(passWord.toCharArray()); // 设置超时时间 单位为秒 options.setConnectionTimeout(10); // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制 options.setKeepAliveInterval(20); //设置回调 client.setCallback(new MqttCallback() { @Override public void connectionLost(Throwable cause) { //连接丢失后,一般在这里面进行重连 System.out.println("connectionLost----------"); //startReconnect(); } @Override public void deliveryComplete(IMqttDeliveryToken token) { //publish后会执行到这里 System.out.println("deliveryComplete---------" + token.isComplete()); } @Override public void messageArrived(String topicName, MqttMessage message) throws Exception { //subscribe后得到的消息会执行到这里面 System.out.println("messageArrived----------"); Message msg = new Message(); msg.what = 3; //收到消息标志位 msg.obj = topicName + "---" + message.toString(); handler.sendMessage(msg); // hander 回传 } }); } catch (Exception e) { e.printStackTrace(); } } private void Mqtt_connect() { new Thread(new Runnable() { @Override public void run() { try { if(!(client.isConnected()) ) //如果还未连接 { client.connect(options); Message msg = new Message(); msg.what = 31; handler.sendMessage(msg); } } catch (Exception e) { e.printStackTrace(); Message msg = new Message(); msg.what = 30; handler.sendMessage(msg); } } }).start(); } private void startReconnect() { scheduler = Executors.newSingleThreadScheduledExecutor(); scheduler.scheduleAtFixedRate(new Runnable() { @Override public void run() { if (!client.isConnected()) { Mqtt_connect(); } } }, 0 * 1000, 10 * 1000, TimeUnit.MILLISECONDS); } private void publishmessageplus(String topic,String message2) { if (client == null || !client.isConnected()) { return; } MqttMessage message = new MqttMessage(); message.setPayload(message2.getBytes()); try { client.publish(topic,message); } catch (MqttException e) { e.printStackTrace(); } } } |
DemoDemo下载
5.总结
半个月前就起草了此篇博客,一直拖拖拉拉,直至今晚才敲定决心坐下搞定它,学习的路上不怕慢,就怕站吧,每个人都会有惰性心理,只有不断克服,勇往直前!
狭路相逢勇者胜!