fix(MqttManager): 防止MQTT客户端重复连接

添加 `isConnecting` 标志位以跟踪连接状态,避免在连接过程中发起新的连接请求。
在连接失败时安全重置客户端,并在连接完成或丢失时正确更新状态标志。
This commit is contained in:
2026-04-20 19:51:36 +08:00
parent 0938a6ad2b
commit 6a3431d741

View File

@@ -36,6 +36,8 @@ class MqttManager(
private val job = SupervisorJob()
private val scope = CoroutineScope(Dispatchers.IO + job)
private var reconnectJob: Job? = null
@Volatile
private var isConnecting: Boolean = false
private val prefs = appContext.getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
private val agentDempIdKey = "agent_demp_id"
@@ -57,10 +59,15 @@ class MqttManager(
private var danceJob: Job? = null
init {
createMqttClient()
}
private fun createMqttClient() {
try {
mqttClient = MqttClient(brokerUri, clientId, MemoryPersistence())
mqttClient?.setCallback(object : MqttCallbackExtended {
override fun connectComplete(reconnect: Boolean, serverURI: String?) {
isConnecting = false
Log.i(TAG, "MQTT connection complete. Reconnect: $reconnect")
subscribeTopic("robot/cmd")
subscribeTopic("soul2user")
@@ -68,6 +75,7 @@ class MqttManager(
}
override fun connectionLost(cause: Throwable?) {
isConnecting = false
Log.e(TAG, "Connection lost: ${cause?.message}")
updateConnectionStatus(false)
scheduleReconnect()
@@ -96,6 +104,10 @@ class MqttManager(
updateConnectionStatus(true)
return@launch
}
if (isConnecting) {
Log.d(TAG, "MQTT connect skipped: already connecting.")
return@launch
}
val username = prefs.getString(HttpManager.PREF_KEY_MQTT_USERNAME, "").orEmpty().trim()
val password = prefs.getString(HttpManager.PREF_KEY_MQTT_PASSWORD, "").orEmpty()
if (username.isEmpty() || password.isEmpty()) {
@@ -103,8 +115,12 @@ class MqttManager(
updateConnectionStatus(false)
return@launch
}
if (mqttClient == null) {
createMqttClient()
}
Log.i(TAG, "Attempting to connect to MQTT broker at $brokerUri")
try {
isConnecting = true
val options = MqttConnectOptions().apply {
isAutomaticReconnect = false
isCleanSession = true
@@ -114,8 +130,10 @@ class MqttManager(
this.password = password.toCharArray()
}
mqttClient?.connect(options)
} catch (e: MqttException) {
Log.e(TAG, "Initial connection failed: ${e.message}")
} catch (t: Throwable) {
Log.e(TAG, "Initial connection failed", t)
isConnecting = false
resetClientSafely()
updateConnectionStatus(false)
scheduleReconnect()
}
@@ -137,6 +155,7 @@ class MqttManager(
scope.launch {
try {
reconnectJob?.cancel()
isConnecting = false
if (mqttClient?.isConnected == true) {
mqttClient?.disconnect()
Log.i(TAG, "Disconnected from MQTT broker.")
@@ -151,7 +170,7 @@ class MqttManager(
fun shutdown() {
reconnectJob?.cancel()
job.cancel()
isConnecting = false
try {
if (mqttClient?.isConnected == true) {
mqttClient?.disconnect()
@@ -165,6 +184,16 @@ class MqttManager(
}
}
private fun resetClientSafely() {
try {
mqttClient?.close()
} catch (_: Exception) {
} finally {
mqttClient = null
}
createMqttClient()
}
private fun updateConnectionStatus(connected: Boolean) {
Handler(Looper.getMainLooper()).post {
statusListener(connected)