客户如何知道它是否已经订阅了MQTT主题?

时间:2019-04-20 02:27:46

标签: kotlin mqtt aws-iot

我正在订阅MQTT主题(在我的情况下,它是应用程序唯一用户ID)。我正在使用AWS IOT核心服务进行订阅。每当打开主屏幕并且从awsConnectClient获得连接回调时,我都会进行要求订阅。现在,如果应用程序打开3次会发生什么呢?它订阅了3次相同的主题。现在,每当有消息发布到该主题时,应用程序就会收到3次。

现在我想做的是,我想知道如果已经从此设备订阅了该userId,那么我将不会再次从同一设备进行订阅。

一种方法是,如果我在应用程序中保存已经订阅了该主题,而不再再次进行订阅。但我怀疑这种方法是否适用于所有情况。是否有可能我们仅从服务器端驱动此逻辑,如果有任何awt iot api可以告诉我该逻辑已被订阅。

fun connectClick() {
    Log.d(TAG, "clientId = $clientId")

    try {
        mqttManager.connect(clientKeyStore) { status, throwable ->
            Log.d(TAG, "Status = " + status.toString())
            var formattedStatus = String.format(getString(R.string.status_msg),status.toString())

            if (status == AWSIotMqttClientStatusCallback.AWSIotMqttClientStatus.Connected) {
                Log.i(TAG, " subscribed to - " + VoiceXPreference(this).rosterName)
                unsubscribe()
                subscribeClick(VoiceXPreference(this).rosterName)
            }
            runOnUiThread {
                tv_iot_status.text = formattedStatus
                if (throwable != null) {
                    Log.e(TAG, "Connection error.", throwable)
                }
            }
        }
    } catch (e: Exception) {
        Log.e(TAG, "Connection error.", e)
    }

}

以上是我的订阅代码。尽管我总是在订阅前退订,但这对我不起作用。

以下是我的initClient调用,它发出了连接请求。我添加了if检查mqttManager是否已经初始化,然后先断开连接,然后发出连接请求。尽管我已将initRequest放在onCreate()内,但会在应用程序打开时调用一次应用程序屏幕。我已经检查了它只被调用过一次的日志。

AWSMobileClient.getInstance().initialize(this, object : Callback<UserStateDetails> {
            override fun onResult(result: UserStateDetails) {
                Log.i(TAG,"connect request called");
                if(mqttManager != null){
                    mqttManager?.disconnect()
                }
                initIoTClient()
            }

            override fun onError(e: Exception) {
                Log.e(TAG, "onError: ", e)
            }
        })

以下是我的订阅代码段,正在订阅唯一的userId

fun subscribeClick(topic: String) {

    Log.d(TAG, "topic = $topic")

    try {
        mqttManager?.subscribeToTopic(topic, AWSIotMqttQos.QOS0,
            { topic, data ->
                runOnUiThread {
                    try {
                        val message = String(data, Charsets.UTF_8)
                        Log.d(TAG, "Message arrived:")
                        Log.d(TAG, "   Topic: $topic")
                        Log.d(TAG, " Message: $message")

                        val gson = Gson()
                        val notificationModel = gson.fromJson(message, NotificationModel::class.java)
                        var orderServiceMapperResponseModel = OrderServiceMapperResponseModel()
                        orderServiceMapperResponseModel.seatId = notificationModel.seatId
                        orderServiceMapperResponseModel.serviceName = notificationModel.service
                        orderServiceMapperResponseModel.id = notificationModel.id
                        orderServiceMapperResponseModel.createdDate = notificationModel.createdDate
                        serviceList.add(orderServiceMapperResponseModel)
                        if (isPictureInPictureMode) {
                            if (isShownNotification) {
                                updateNotificationCount()
                            } else {
                                updatePIPWindowContent()
                            }
                        } else {
                            updateAdapterDataSource()
                        }

                    } catch (e: UnsupportedEncodingException) {
                        Log.e(TAG, "Message encoding error.", e)
                    }
                }
            })
    } catch (e: Exception) {
        Log.e(TAG, "Subscription error.", e)
    }
}

我也总是在我的应用程序屏幕的onDestroy()内部发出断开连接()请求

mqttManager?.disconnect()

但是我仍然收到3条订阅消息,而不是1条。

1 个答案:

答案 0 :(得分:0)

您收到3条重复的消息不是因为您订阅了3次,而是因为您创建了3条单独的连接。

MQTT specification明确指出

  

如果服务器收到的SUBSCRIBE数据包中包含与现有订阅的主题过滤器相同的主题过滤器,则它必须用新的订阅完全替换该现有订阅。

意味着永远不会发生每个连接重复的预订,除非服务器的实现有问题。

您的代码看起来像在调用代码块时创建新连接时从不发送断开连接请求。

您应该保留一个MQTT会话,或者确保在应用关闭时关闭连接。