1. Basic Usage of MQTT
1. Add Dependencies
// build.gradle (app)
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
2. Configure Permissions
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<service android:name="org.eclipse.paho.android.service.MqttService" />
3. Core Code Example
class MqttManager(context: Context) {
private val serverUri = "tcp://mqtt.eclipse.org:1883"
private val clientId = "android-client-[0m${System.currentTimeMillis()}"
private val qos = 1
private var mqttClient: MqttAndroidClient? = null
init {
mqttClient = MqttAndroidClient(context, serverUri, clientId).apply {
setCallback(object : MqttCallback {
override fun messageArrived(topic: String, message: MqttMessage) {
Log.d("MQTT", "Received: [0m${String(message.payload)}")
}
override fun connectionLost(cause: Throwable) {
Log.e("MQTT", "Connection lost", cause)
}
override fun deliveryComplete(token: IMqttDeliveryToken) {}
})
}
}
// Connect to the server
fun connect() {
try {
val options = MqttConnectOptions().apply {
isCleanSession = true
keepAliveInterval = 60
userName = "username" // Optional
password = "password".toCharArray() // Optional
}
mqttClient?.connect(options, null, object : IMqttActionListener {
override fun onSuccess(asyncActionToken: IMqttToken) {
subscribe("topic/example")
}
override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) {
Log.e("MQTT", "Connection failed", exception)
}
})
} catch (e: MqttException) {
e.printStackTrace()
}
}
// Subscribe to a topic
fun subscribe(topic: String) {
mqttClient?.subscribe(topic, qos, null, object : IMqttActionListener {
override fun onSuccess(asyncActionToken: IMqttToken) {
Log.d("MQTT", "Subscribed to $topic")
}
override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) {
Log.e("MQTT", "Subscribe failed", exception)
}
})
}
// Publish a message
fun publish(topic: String, message: String) {
try {
val mqttMessage = MqttMessage(message.toByteArray()).apply {
qos = [email protected]
isRetained = false
}
mqttClient?.publish(topic, mqttMessage)
} catch (e: MqttException) {
e.printStackTrace()
}
}
// Disconnect
fun disconnect() {
mqttClient?.disconnect()
}
}
2. Common Problems and Solutions
1. Connection Failure
Problem Manifestation:<span>MqttException (0) - MqttException</span>
- Possible Causes:
- Network unavailable
- Incorrect server address/port
- Protocol version mismatch (e.g., server requires MQTT 3.1.1)
- Solution:
val options = MqttConnectOptions().apply { mqttVersion = MqttConnectOptions.MQTT_VERSION_3_1_1 // Force protocol version }
2. Message Loss
Problem Manifestation: Subscription client does not receive messages after publishing
- Possible Causes:
- QoS level set too low (0)
- Client does not maintain persistent session
- Solution:
// Use QoS 1 or 2 when publishing mqttMessage.qos = 2 // Enable persistent session when connecting options.isCleanSession = false
3. Background Running Limitations
Problem Manifestation: Disconnects when the app goes to the background
- Solution: Use a foreground service to maintain connection
// Start in Service val notification = NotificationCompat.Builder(this, "mqtt_channel") .setContentTitle("MQTT Service") .setSmallIcon(R.drawable.ic_notification) .build() startForeground(1, notification)
4. Certificate Verification Failure (SSL/TLS)
Problem Manifestation:<span>javax.net.ssl.SSLHandshakeException</span>
- Solution: Use a custom SSLSocketFactory
val sslContext = SSLContext.getInstance("TLSv1.2") sslContext.init(null, trustAllCerts, SecureRandom()) options.socketFactory = sslContext.socketFactory
5. Memory Leak
Problem Manifestation: Callbacks still execute after Activity is destroyed
- Solution: Lifecycle binding
class MainActivity : AppCompatActivity() { private lateinit var mqttManager: MqttManager override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mqttManager = MqttManager(this) mqttManager.connect() } override fun onDestroy() { mqttManager.disconnect() super.onDestroy() } }
6. Duplicate Message Reception
Problem Manifestation: Receiving duplicate messages (QoS 1/2 scenarios)
- Solution: Implement a message deduplication mechanism
private val receivedMessageIds = mutableSetOf<String>() override fun messageArrived(topic: String, message: MqttMessage) { val messageId = message.id.toString() if (!receivedMessageIds.contains(messageId)) { receivedMessageIds.add(messageId) // Process message } }
3. Best Practices
- Connection Management:
- Use
<span>keepAliveInterval</span>
to maintain heartbeat - Implement automatic reconnection mechanism
- MQTT callbacks execute on non-UI threads, need to use
<span>runOnUiThread</span>
to update UI
- Real-time data: QoS 0
- Important notifications: QoS 1
- Critical commands: QoS 2
- Use hierarchical structure:
<span>sensors/temperature/room1</span>
- Avoid using
<span>#</span>
wildcard to subscribe to too many topics
By implementing the above methods and considerations, MQTT communication can be integrated stably and efficiently in Android applications.
Follow me for more knowledge or to contribute