java代码
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
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;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private MqttClient mqttClient;
private TextView connectionStatusTextView;
private ImageView ledStatusImageView;
private boolean isConnecting = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
//使用AsyncTask异步,当执行execute时会自动开辟一个线程
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
connectionStatusTextView =(TextView) findViewById(R.id.connection_status_text_view);
ledStatusImageView = findViewById(R.id.ledStatusImageView);
Button connectBtn = findViewById(R.id.connectBtn);
connectBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!isConnecting) {
new ConnectTask().execute();
}
}
});
Button reconnectBtn = findViewById(R.id.reconnectBtn);
reconnectBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!isConnecting) {
new ReconnectTask().execute();
}
}
});
Button disconnectBtn = findViewById(R.id.disconnectBtn);
disconnectBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new DisconnectTask().execute();
}
});
Button toggleLedBtn = findViewById(R.id.toggleLED);
toggleLedBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new ToggleLedTask().execute("led1");
}
});
Button toggleLed2Btn = findViewById(R.id.toggleLED2);
toggleLed2Btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new ToggleLedTask().execute("led2");
}
});
}
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()
*/
@Override
protected void onPreExecute() //执行耗时操作之前处理UI线程事件
{
super.onPreExecute();
isConnecting = true;
connectionStatusTextView.setText("Connecting...");
}
@Override
protected Boolean doInBackground(Void... voids)
{
//在此方法执行耗时操作,耗时操作中收发MQTT服务器的数据
//MQTT服务器地址
String brokerUrl = "tcp://iot.eclipse.org: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());
try {
mqttClient.connect(connectOptions);
mqttClient.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable throwable) {
Log.d(TAG, "connectionLost: " + throwable.getMessage());
publishProgress("Connection lost, reconnecting...");
new ReconnectTask().execute();
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
Log.d(TAG, "messageArrived: " + message.toString());
if (topic.equals("sensors/temperature")) {
// Update temperature reading
publishProgress("Temperature: " + message.toString());
} else if (topic.equals("sensors/humidity")) {
// Update humidity reading
publishProgress("Humidity: " + message.toString());
} else if (topic.equals("leds/led1/status")) {
// Update LED 1 status
if (message.toString().equals("on")) {
publishProgress("LED 1 is on");
ledStatusImageView.setImageResource(R.drawable.light_on_background);
} else {
publishProgress("LED 1 is off");
ledStatusImageView.setImageResource(R.drawable.light_off_background);
}
} else if (topic.equals("leds/led2/status")) {
// Update LED 2 status
if (message.toString().equals("on")) {
publishProgress("LED 2 is on");
ledStatusImageView.setImageResource(R.drawable.light_on_background);
} else {
publishProgress("LED 2 is off");
ledStatusImageView.setImageResource(R.drawable.light_off_background);
}
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
Log.d(TAG, "deliveryComplete");
}
});
//这里是订阅的话题
mqttClient.subscribe("sensors/temperature");
mqttClient.subscribe("sensors/humidity");
mqttClient.subscribe("leds/led1/status");
mqttClient.subscribe("leds/led2/status");
} 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;
}
@Override
protected void onProgressUpdate(String... values) {
//用于在主线程处理doInBackground()方法执行完毕后的结果,更新UI或者执行其它操作
super.onProgressUpdate(values);
connectionStatusTextView.setText(values[0]);
}
@Override
protected void onPostExecute(Boolean aBoolean)
{
//用于在主线程处理doInBackground()方法执行完毕后的结果,更新UI或者执行其它操作
super.onPostExecute(aBoolean);
isConnecting = false;
if (aBoolean) {
connectionStatusTextView.setText("Connected");
}
}
}
private class ReconnectTask extends AsyncTask<Void, String, Boolean> {
@Override
protected void onPreExecute() {
super.onPreExecute();
isConnecting = true;
connectionStatusTextView.setText("Reconnecting...");
}
@Override
protected 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();
}
@Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
isConnecting = false;
if (aBoolean) {
connectionStatusTextView.setText("Connected");
}
}
}
private class DisconnectTask extends AsyncTask<Void, Void, Void> {
@Override
protected void onPreExecute() {
super.onPreExecute();
connectionStatusTextView.setText("Disconnecting...");
}
@Override
protected Void 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 null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
connectionStatusTextView.setText("Disconnected");
ledStatusImageView.setImageResource(R.drawable.light_off_background);
}
}
private class ToggleLedTask extends AsyncTask<String, Void, Void> {
@Override
protected Void doInBackground(String... strings) {
if (mqttClient != null && mqttClient.isConnected()) {
String topic = "leds/" + strings[0] + "/control";
MqttMessage message = new MqttMessage();
if (ledStatusImageView.getDrawable().getConstantState().equals(getResources().getDrawable(R.drawable.light_on_background).getConstantState())) {
message.setPayload("off".getBytes());
} else {
message.setPayload("on".getBytes());
}
try {
mqttClient.publish(topic, message);
} catch (MqttException e) {
Log.e(TAG, "Error publishing message: " + e.getMessage());
}
}
return null;
}
}
}
xml文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 连接、重连、断开连接按钮 -->
<Button
android:id="@+id/connectBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Connect"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp"/>
<Button
android:id="@+id/reconnectBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Reconnect"
android:layout_below="@id/connectBtn"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp"/>
<Button
android:id="@+id/disconnectBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Disconnect"
android:layout_below="@id/reconnectBtn"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp"/>
<!-- 连接状态显示 -->
<TextView
android:id="@+id/connection_status_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Disconnected"
android:layout_below="@id/disconnectBtn"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp"/>
<!-- 传感器数据显示 -->
<TextView
android:id="@+id/sensorDataTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sensor Data:"
android:layout_below="@id/disconnectBtn"
android:layout_alignParentStart="true"
android:layout_marginTop="16dp"/>
<TextView
android:id="@+id/sensorDataValueTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:layout_alignBaseline="@id/sensorDataTextView"
android:layout_toEndOf="@id/sensorDataTextView"
android:layout_marginStart="16dp"/>
<!-- 小灯控制按钮 -->
<Button
android:id="@+id/toggleLED"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Toggle LED 1"
android:layout_below="@id/sensorDataValueTextView"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp"/>
<Button
android:id="@+id/toggleLED2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Toggle LED 2"
android:layout_below="@id/toggleLED"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp"/>
<!-- 小灯状态显示 -->
<ImageView
android:id="@+id/ledStatusImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/light_off_background"
android:layout_below="@id/toggleLED2"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp"/>
</RelativeLayout>
声明文件Manifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mqtttest">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="org.eclipse.paho.android.service.MqttService" />
</application>
</manifest>
以上程序
在onCreate()方法中,初始化UI控件和MQTT客户端。其中,connectBtn按钮用于连接MQTT服务器,disconnectBtn按钮用于断开连接,reconnectBtn按钮用于重新连接。toggleLED和toggleLED2按钮用于控制两个小灯的开关。tempTextView和humidityTextView文本框用于显示传感器的温度和湿度数据,connectionStatusTextView文本框用于显示MQTT连接状态。mqttAndroidClient是一个MQTT客户端实例,用于连接MQTT服务器和进行消息的订阅和发布。
在connectBtn的onClick()方法中,调用connect()方法连接MQTT服务器,并在连接成功后订阅主题。在连接失败时,会弹出提示框提示连接失败。
在disconnectBtn的onClick()方法中,调用disconnect()方法断开MQTT服务器的连接。
在reconnectBtn的onClick()方法中,调用reconnect()方法重新连接MQTT服务器。
在toggleLED和toggleLED2的onClick()方法中,根据按钮状态发送控制指令到MQTT服务器,控制对应的小灯的开关状态。
在connect()方法中,设置MQTT客户端的各种参数,如服务器地址、客户端ID、保持连接的时间间隔、连接超时时间、是否清除会话等。然后调用connect()方法连接MQTT服务器,并设置连接成功和连接失败的回调函数。在连接成功后,订阅主题TOPIC。
在disconnect()方法中,调用MQTT客户端的disconnect()方法断开与MQTT服务器的连接。
在reconnect()方法中,判断当前是否已连接MQTT服务器。如果已连接,则先断开连接,然后重新连接MQTT服务器。
在subscribeToTopic()方法中,订阅指定主题TOPIC。当收到对应主题的消息时,会调用messageArrived()方法进行处理。
在publishMessage()方法中,向指定主题TOPIC发布指定内容的消息。
在messageArrived()方法中,处理收到的消息,更新温度和湿度数据,并根据收到的消息更新小灯的状态。
在connect()方法中,设置MQTT客户端的各种参数,如服务器地址、客户端ID、保持连接的时间间隔、连接超时时间、是否清除会话等。然后调用connect()方法连接MQTT服务器,并设置连接成功和连接失败的回调函数。在连接成功后,订阅主题TOPIC。
在disconnect()方法中,调用MQTT客户端的disconnect()方法断开与MQTT服务器的连接。
在reconnect()方法中,判断当前是否已连接MQTT服务器。如果已连接,则先断开连接,然后重新连接MQTT服务器。
在subscribeToTopic()方法中,订阅指定主题TOPIC。当收到对应主题的消息时,会调用messageArrived()方法进行处理。
在publishMessage()方法中,向指定主题TOPIC发布指定内容的消息。
在messageArrived()方法中,处理收到的消息,更新温度和湿度数据,并根据收到的消息更新小灯的状态。