Как клиент может узнать, подписан ли он уже на тему MQTT? - PullRequest
0 голосов
/ 20 апреля 2019

Я подписываюсь на тему MQTT (в моем случае это уникальный идентификатор пользователя приложения). Я использую основные сервисы AWS IOT для подписки. Когда открывается домашний экран, и я получаю ответный вызов от awsConnectClient, я делаюпозвоните для подписки.Теперь, что происходит, если приложение открывается три раза. Оно подписывается на одну и ту же тему 3 раза. Теперь, когда любое сообщение публикуется в этой теме. Оно получено приложением 3 раза.

Теперь, что я хочу сделать, яхочу знать, что если бы этот userId уже был подписан с этого устройства, я бы не стал повторно вызывать подписку с того же устройства.

Один из подходов может быть, если я сохраню в своем приложении то, что я уже подписался на эту темуи не звоните для подписки снова.но я сомневаюсь, что этот подход может быть правильным для всех сценариев. Возможно ли, что мы сможем использовать эту логику только со стороны сервера, если какой-либо aws 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, который выполняет запрос на подключение.Я добавил, если проверка, если 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 голосов
/ 20 апреля 2019

Вы получаете 3 дублированных сообщения не потому, что вы подписались 3 раза, а , потому что вы создаете 3 отдельных соединения .

В спецификации MQTT четко указано, что

Если сервер получает пакет SUBSCRIBE, содержащий фильтр тем, который идентичен фильтру тем существующей подписки, он ДОЛЖЕН полностью заменить существующую подписку новой подпиской.

означает, что дублированные подписки на соединение никогда не произойдут, если только у сервера нет сломанной реализации.

Ваш код выглядит так, что он никогда не отправляет запросы на отключение, пока новое соединение создается при каждом вызове блока кода.

Вы должны сохранить один сеанс MQTT или убедиться, что закрыли соединение, когда приложение закрыто.

...